Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-30 Thread Jonathan M Davis via Digitalmars-d
On Tuesday, May 30, 2017 19:00:12 Kagamin via Digitalmars-d wrote:
> On Saturday, 27 May 2017 at 16:27:46 UTC, Ola Fosheim Grøstad
>
> wrote:
> > If the semantics in C is that everything is typed shared then
> > it should also be treated as such when D interfaces with C and
> > C like type-semantics.
>
> Then you would need to laboriously mark everything related to C
> as shared, which would be quite different from C workflow.

Everything is shared is C, but it's not marked as shared, so even though
almost all of it is used as if it were thread-local, it isn't actually
guaranteed to be so. This means that if you were being paranoid about it,
you'd have to treat every C API as shared, but that is completely
impractical and rarely fits what the C API actually does. In the vast
majority of cases, if the C code were translated to D code, it would be
translated as thread-local and be just fine. Well-behaved C code acts like D
code in that it segregates code that operates on data as if it's on one
thread and code that operates on data that's shared across threads, even if
C doesn't have the helper attributes that D does.

So, when dealing with a C API and shared, it's a bit like dealing with
@system/@trusted and C APIs. With @system/@trusted, it's up to the
programmer to figure out what's safe and what isn't based on what the API
does. If it's appropriately memory-safe, then it's okay to mark it as
@trusted, and if there's a problem, then you know that you need to dig into
the C code to fix it. If it's not memory-safe, then it needs to be marked
with @system (or nothing), and the programmer needs to make sure that they
use it correctly in order to make the code that uses it memory-safe.

With C APIs and shared, the programmer needs to be sure of whether it's
thread-safe to treat that API call as if it's operating on thread-local
data, or whether it needs to be treated as operating on shared data, and
then mutexes need to be used as appropriate. Fortunately, it's usually
clear, and in the vast majority of cases, treating the C function as
operating on thread-local data is just fine. But it is true that you need to
be a bit careful when binding to C APIs to make sure that something which
isn't thread-safe is not treated as thread-local.

- Jonathan M Davis




Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-30 Thread Kagamin via Digitalmars-d
On Saturday, 27 May 2017 at 16:27:46 UTC, Ola Fosheim Grøstad 
wrote:
If the semantics in C is that everything is typed shared then 
it should also be treated as such when D interfaces with C and 
C like type-semantics.


Then you would need to laboriously mark everything related to C 
as shared, which would be quite different from C workflow.


Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-27 Thread Ola Fosheim Grøstad via Digitalmars-d

On Saturday, 27 May 2017 at 16:19:06 UTC, Kagamin wrote:
On Saturday, 27 May 2017 at 10:29:05 UTC, Ola Fosheim Grøstad 
wrote:
Hm, I would think that using __gshared would not be affected 
by compiler improvements, since it would turn off 
optimizations that assume that the variable doesn't change 
between reads?


Like volatile? Volatile doesn't work.


Volatile is different. Volatile means there can be side-effects 
from reads/writes, so the compiler cannot optimize out writes. 
This is for hardware registers.


__gshared has purpose to behave like old good global variable 
simply to provide a low level feature for a system language, if 
you need something else, then use the right tool.


Doesn't make much sense to me.

If the semantics in C is that everything is typed shared then it 
should also be treated as such when D interfaces with C and C 
like type-semantics.




Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-27 Thread Kagamin via Digitalmars-d
On Saturday, 27 May 2017 at 10:29:05 UTC, Ola Fosheim Grøstad 
wrote:
Hm, I would think that using __gshared would not be affected by 
compiler improvements, since it would turn off optimizations 
that assume that the variable doesn't change between reads?


Like volatile? Volatile doesn't work. Why would you want that? 
__gshared has purpose to behave like old good global variable 
simply to provide a low level feature for a system language, if 
you need something else, then use the right tool.


Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-27 Thread Kagamin via Digitalmars-d

On Saturday, 27 May 2017 at 10:02:35 UTC, Jonathan M Davis wrote:
Actually, not so much, because in D, most variables are _not_ 
shared across threads (unlike in C).


If you don't share data, you don't need to worry how to share 
data. But if you do, D supports C model.


The compiler is free to assume that if a variable is not marked 
as shared, it's thread-local, and it can optimize accordingly.


Just like in C.

Using __gshared on anything other than C globals is just 
begging for trouble.


Just like in C.

As such, I'd strongly argue that using __gshared with anything 
other than actual C globals is a serious code smell, and it's a 
practice that should be actively discouraged.


You can't just discourage to write code. What to do instead, open 
a bakery?


Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-27 Thread Ola Fosheim Grøstad via Digitalmars-d

On Saturday, 27 May 2017 at 11:52:04 UTC, John Colvin wrote:

Nope. __gshared isn't even part of the type so it can't do that.

__gshared int a;

void main()
{
foo(a);


But this should fail since foo doesn't take shared?

__gshared is a way of declaring a C-like global variable, but D 
does not - in general - support accessing it in a C-like way. 
My advice is to cast to shared before use, unless you're 
totally sure you know what other threads will be doing.


Why isn't it always typed as shared?



Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-27 Thread John Colvin via Digitalmars-d
On Saturday, 27 May 2017 at 10:29:05 UTC, Ola Fosheim Grøstad 
wrote:
On Saturday, 27 May 2017 at 10:02:35 UTC, Jonathan M Davis 
wrote:
As such, the fact that D programmers frequently decide to use 
__gshared in order to avoid dealing with the restrictions with 
shared is actually extremely bad. You can get away with it in 
some cases, but it's error-prone and is only going to get 
worse as the compiler improves.


Hm, I would think that using __gshared would not be affected by 
compiler improvements, since it would turn off optimizations 
that assume that the variable doesn't change between reads?


Nope. __gshared isn't even part of the type so it can't do that.

__gshared int a;

void main()
{
foo(a);
}

void foo(ref int b)
{
// No way of knowing that b actually
// references __gshared memory.
}

__gshared is a way of declaring a C-like global variable, but D 
does not - in general - support accessing it in a C-like way. My 
advice is to cast to shared before use, unless you're totally 
sure you know what other threads will be doing.


Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-27 Thread Ola Fosheim Grøstad via Digitalmars-d

On Saturday, 27 May 2017 at 10:02:35 UTC, Jonathan M Davis wrote:
As such, the fact that D programmers frequently decide to use 
__gshared in order to avoid dealing with the restrictions with 
shared is actually extremely bad. You can get away with it in 
some cases, but it's error-prone and is only going to get worse 
as the compiler improves.


Hm, I would think that using __gshared would not be affected by 
compiler improvements, since it would turn off optimizations that 
assume that the variable doesn't change between reads?




Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-27 Thread Jonathan M Davis via Digitalmars-d
On Saturday, May 27, 2017 07:20:10 Kagamin via Digitalmars-d wrote:
> On Thursday, 25 May 2017 at 14:56:25 UTC, Jonathan M Davis wrote:
> > But we do need to get this ironed out well enough that we can
> > definitely tell folks that shared is what it's going to be so
> > that they'll stop using __gshared all over the place to try and
> > work around shared - or at least if they do so, they won't be
> > able to do so with the excuse that shared is not complete.
>
> People don't have to use shared, D supports old good "anything
> can be shared" C model, if people think C model is good enough
> for them, they can use it.

Actually, not so much, because in D, most variables are _not_ shared across
threads (unlike in C). The compiler is free to assume that if a variable is
not marked as shared, it's thread-local, and it can optimize accordingly.
Using __gshared on anything other than C globals is just begging for
trouble. As such, the fact that D programmers frequently decide to use
__gshared in order to avoid dealing with the restrictions with shared is
actually extremely bad. You can get away with it in some cases, but it's
error-prone and is only going to get worse as the compiler improves. As
such, I'd strongly argue that using __gshared with anything other than
actual C globals is a serious code smell, and it's a practice that should be
actively discouraged.

- Jonathan M Davis



Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-27 Thread Kagamin via Digitalmars-d

On Thursday, 25 May 2017 at 14:56:25 UTC, Jonathan M Davis wrote:
But we do need to get this ironed out well enough that we can 
definitely tell folks that shared is what it's going to be so 
that they'll stop using __gshared all over the place to try and 
work around shared - or at least if they do so, they won't be 
able to do so with the excuse that shared is not complete.


People don't have to use shared, D supports old good "anything 
can be shared" C model, if people think C model is good enough 
for them, they can use it.


Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-26 Thread Paul Backus via Digitalmars-d

On Wednesday, 24 May 2017 at 23:56:49 UTC, Timothee Cour wrote:
I could look at source to figure it out but others might wonder 
and I couldn't find it in the docs in 
https://dlang.org/library/std/functional/memoize.html whether 
memoize works per thread (thread local) or globally (__gshared)


I checked the source, and it's thread-local. (Specifically, it's 
declared as 'static'.)


Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-25 Thread Ola Fosheim Grostad via Digitalmars-d

On Thursday, 25 May 2017 at 20:43:36 UTC, Jonathan M Davis wrote:
complication to the language. Certainly, from what I know of 
Rust, it's far more complicated because of that sort of thing, 
and glancing over that link on Pony, it looks like it's getting 
a fair bit of complication as well in order to deal with the 
problem.


I think Pony uses a GC (also to collect dead threads/actors).

But I have found that trying to understand their model to be a 
good exercise for thinking about where problems can arise and 
what it takes to resolve it through a typesystem.


stuff with regards to threads to shared, which is great, but 
dealing with the stuff that involves sharing across threads 
then requires that the programmer be much more careful than 
would be the case if the type system were actually helping you 
beyond preventing you from doing stuff that isn't thread safe 
to a shared object without casting it to thread-local first.


Yes, that transition to/from shared is problematic. There are 
ways to deal with it, proving concurrency patterns to be correct, 
but it takes even more machinery than Pony/Rust.


I don't know what the right answer is. Rust seems to get both 
praise and complaints about its approach - as do we for ours. 
But both approaches are safer than what you get with C/C++.


Depends on what you do in C++. If you only share though a 
ready-made framework, then you probably can do quite well in 
terms of safety. With a small performance cost.


If you want max performance in the general case then I think all 
these languages will have safety troubles. Because you need 
proper full-blown verification then...





Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-25 Thread Jack Stouffer via Digitalmars-d

On Thursday, 25 May 2017 at 11:15:19 UTC, Stanislav Blinov wrote:

Count me const scope.


https://www.youtube.com/watch?v=YIp-0V6YKfQ


Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-25 Thread Jonathan M Davis via Digitalmars-d
On Thursday, May 25, 2017 19:57:17 Ola Fosheim Grøstad via Digitalmars-d 
wrote:
> On Thursday, 25 May 2017 at 14:56:25 UTC, Jonathan M Davis wrote:
> > able to do so with the excuse that shared is not complete. But
> > the idea that you do almost nothing with an object that is
> > shared without casting it first (after protecting it
> > appropriately with a mutex of course) except for using atomics
> > seems to be too much for many folks, even though aside from the
> > cast, the way you actually use a shared object is basically
> > what you'd do in C/C++. I'd say that ultimately, shared is more
> > for storing the object and protecting it against operations
> > that could operate on it incorrectly than it is for actually
> > operating on the object.
>
> You should look at Pony which has a sound type system for
> transitioning objects read/write local/shared:
>
> https://tutorial.ponylang.org/capabilities/reference-capabilities.html
>
> It is kinda like Rust, but more advanced.

Oh, having some sort of ownership model or something similar in the type
system which made it possible to know when something was only referenced
once on a thread and thus could be passed safely to another and things like
that would be very cool. For instance, it would make std.concurrency far
easier to use safely with mutable data. The problem is that it seems that in
order to for that to be possible, it adds quite a bit of complication to the
language. Certainly, from what I know of Rust, it's far more complicated
because of that sort of thing, and glancing over that link on Pony, it
looks like it's getting a fair bit of complication as well in order to deal
with the problem.

With D, having shared (and thus having everything else be thread-local)
simplifies a lot of stuff, leaving the nasty stuff with regards to threads
to shared, which is great, but dealing with the stuff that involves sharing
across threads then requires that the programmer be much more careful than
would be the case if the type system were actually helping you beyond
preventing you from doing stuff that isn't thread safe to a shared object
without casting it to thread-local first. So, we're stuck with an annoying
area that would be great to clean up, but cleaning it up seems like it
requires complicating everything else...

I don't know what the right answer is. Rust seems to get both praise and
complaints about its approach - as do we for ours. But both approaches are
safer than what you get with C/C++.

- Jonathan M Davis




Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-25 Thread Ola Fosheim Grøstad via Digitalmars-d

On Thursday, 25 May 2017 at 14:56:25 UTC, Jonathan M Davis wrote:
able to do so with the excuse that shared is not complete. But 
the idea that you do almost nothing with an object that is 
shared without casting it first (after protecting it 
appropriately with a mutex of course) except for using atomics 
seems to be too much for many folks, even though aside from the 
cast, the way you actually use a shared object is basically 
what you'd do in C/C++. I'd say that ultimately, shared is more 
for storing the object and protecting it against operations 
that could operate on it incorrectly than it is for actually 
operating on the object.


You should look at Pony which has a sound type system for 
transitioning objects read/write local/shared:


https://tutorial.ponylang.org/capabilities/reference-capabilities.html

It is kinda like Rust, but more advanced.



Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-25 Thread Jonathan M Davis via Digitalmars-d
On Thursday, May 25, 2017 10:41:23 Andrei Alexandrescu via Digitalmars-d 
wrote:
> On Thursday, 25 May 2017 at 03:51:05 UTC, Stanislav Blinov wrote:
> > On Thursday, 25 May 2017 at 01:17:41 UTC, Timothee Cour wrote:
> >> thanks; i think docs for this should still make that clear.
> >>
> >> How about adding memoizeShared for shared variables?
> >> There definitely are use cases for this.
> >
> > Perhaps we should first actually properly document and
> > implement what shared *is*.
>
> I'm looking into creating a small interest group composed of
> experts to lead this effort. We'd put a DIP together that nails
> down shared. Who is interested? -- Andrei

I would be, though it is one of those topics where you think that you know
what you're doing, and then you find out about some compiler optimization or
other low level item that you don't know about, and some of what you thought
was true wasn't. So, this is one area where I'm not sure that I'd ever be
willing to call myself an expert no much how much I knew.

But we do need to get this ironed out well enough that we can definitely
tell folks that shared is what it's going to be so that they'll stop using
__gshared all over the place to try and work around shared - or at least if
they do so, they won't be able to do so with the excuse that shared is not
complete. But the idea that you do almost nothing with an object that is
shared without casting it first (after protecting it appropriately with a
mutex of course) except for using atomics seems to be too much for many
folks, even though aside from the cast, the way you actually use a shared
object is basically what you'd do in C/C++. I'd say that ultimately, shared
is more for storing the object and protecting it against operations that
could operate on it incorrectly than it is for actually operating on the
object. Unfortunately, synchronized classes are the only construct that
we've come up with that allows for the locking and casting to to be done
safely and automatically rather than requiring an explicit cast, and not
only do we not have synchronized classes yet, but even if we did they would
only work on the outer layer of shared, so in many cases, you'd be forced to
cast anyway.

I think that ultimately the big problems that we need to solve are making it
clear what shared is and how you use it and ensuring that we have the memory
model stuff ironed out well enough that the required casting and other
operations are actually guaranteed to do what they're supposed to do. Then
it's an issue of educating folks about shared rather than needing to fix
anything about it. I don't expect that shared will never be entirely pretty,
but ultimately, it's a lot like @safe/@system/@trusted in that it allows you
to segregate the code that you need to worry about for a particular class of
problem - and ultimately, the biggest benefit of shared is that everything
else is thread-local.

- Jonathan M Davis



Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-25 Thread Stanislav Blinov via Digitalmars-d
On Thursday, 25 May 2017 at 10:41:23 UTC, Andrei Alexandrescu 
wrote:
On Thursday, 25 May 2017 at 03:51:05 UTC, Stanislav Blinov 
wrote:

On Thursday, 25 May 2017 at 01:17:41 UTC, Timothee Cour wrote:

thanks; i think docs for this should still make that clear.

How about adding memoizeShared for shared variables?
There definitely are use cases for this.



Perhaps we should first actually properly document and 
implement what shared *is*.


I'm looking into creating a small interest group composed of 
experts to lead this effort. We'd put a DIP together that nails 
down shared. Who is interested? -- Andrei


Count me const scope.


Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-25 Thread Andrei Alexandrescu via Digitalmars-d

On Thursday, 25 May 2017 at 03:51:05 UTC, Stanislav Blinov wrote:

On Thursday, 25 May 2017 at 01:17:41 UTC, Timothee Cour wrote:

thanks; i think docs for this should still make that clear.

How about adding memoizeShared for shared variables?
There definitely are use cases for this.



Perhaps we should first actually properly document and 
implement what shared *is*.


I'm looking into creating a small interest group composed of 
experts to lead this effort. We'd put a DIP together that nails 
down shared. Who is interested? -- Andrei


Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-24 Thread Stanislav Blinov via Digitalmars-d

On Thursday, 25 May 2017 at 01:17:41 UTC, Timothee Cour wrote:

thanks; i think docs for this should still make that clear.

How about adding memoizeShared for shared variables?
There definitely are use cases for this.



Perhaps we should first actually properly document and implement 
what shared *is*.





Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-24 Thread Timothee Cour via Digitalmars-d
thanks; i think docs for this should still make that clear.

How about adding memoizeShared for shared variables?
There definitely are use cases for this.


On Wed, May 24, 2017 at 5:19 PM, Jonathan M Davis via Digitalmars-d
 wrote:
> On Wednesday, May 24, 2017 16:56:49 Timothee Cour via Digitalmars-d wrote:
>> I could look at source to figure it out but others might wonder and I
>> couldn't find it in the docs in
>> https://dlang.org/library/std/functional/memoize.html whether memoize
>> works per thread (thread local) or globally (__gshared)
>
> Definitely thread-local, and there would be problems if it were shared,
> since for that to work properly, it would really need to be given either
> shared data or data that implicitly converted to shared. And while __gshared
> might skirt the compiler yelling at you, it would have the same issues; it's
> just that the compiler wouldn't be yelling at you about them, so it would be
> harder to catch them and more likely that you'd get weird,
> hard-to-track-down bugs.
>
> - Jonathan M Davis
>


Re: std.functional.memoize : thread local or __gshared memoization?

2017-05-24 Thread Jonathan M Davis via Digitalmars-d
On Wednesday, May 24, 2017 16:56:49 Timothee Cour via Digitalmars-d wrote:
> I could look at source to figure it out but others might wonder and I
> couldn't find it in the docs in
> https://dlang.org/library/std/functional/memoize.html whether memoize
> works per thread (thread local) or globally (__gshared)

Definitely thread-local, and there would be problems if it were shared,
since for that to work properly, it would really need to be given either
shared data or data that implicitly converted to shared. And while __gshared
might skirt the compiler yelling at you, it would have the same issues; it's
just that the compiler wouldn't be yelling at you about them, so it would be
harder to catch them and more likely that you'd get weird,
hard-to-track-down bugs.

- Jonathan M Davis



std.functional.memoize : thread local or __gshared memoization?

2017-05-24 Thread Timothee Cour via Digitalmars-d
I could look at source to figure it out but others might wonder and I
couldn't find it in the docs in
https://dlang.org/library/std/functional/memoize.html whether memoize
works per thread (thread local) or globally (__gshared)