www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - How does pragma(lib) work?

reply dsimcha <dsimcha yahoo.com> writes:
When I add the directive:

pragma(lib, "foo");

to a file called "bar.d" and then do:

dmd -c bar.d

does the object file bar.o or bar.obj contain a directive that reflects 
the pragma, or does pragma(lib) only work when compiling and linking in 
one step, e.g. dmd bar.d?
Aug 27 2011
next sibling parent reply Robert Clipsham <robert octarineparrot.com> writes:
On 27/08/2011 16:59, dsimcha wrote:
 When I add the directive:

 pragma(lib, "foo");

 to a file called "bar.d" and then do:

 dmd -c bar.d

 does the object file bar.o or bar.obj contain a directive that reflects
 the pragma, or does pragma(lib) only work when compiling and linking in
 one step, e.g. dmd bar.d?

pragma(lib) only works with one step compilation - it's useless if you want one-at-a-time compilation, hence why rebuild and other tools had pragma(link). -- Robert http://octarineparrot.com/
Aug 27 2011
next sibling parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
After having used the D 2.0 programming language for a year now and 
having completed 3 projects with it, I wrote a small article about the 
problems I had with the D 2.0 programming language and what suggestions 
I have to improve it.

http://3d.benjamin-thaut.de/?p=18

Comments and criticism welcome

-- 
Kind Regards
Benjamin Thaut
Aug 27 2011
next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
On 8/27/2011 1:14 PM, Benjamin Thaut wrote:
 After having used the D 2.0 programming language for a year now and
 having completed 3 projects with it, I wrote a small article about the
 problems I had with the D 2.0 programming language and what suggestions
 I have to improve it.

 http://3d.benjamin-thaut.de/?p=18

 Comments and criticism welcome

Excellent article. I like the constructive criticism without the "D will never be better than C++, Walter Bright is an idiot, I will never use a GC language, D is slow on one benchmark therefore it is poorly designed and will be slow forever" attitude. Some of the things you mention are definitely bugs. (I'd call emplace requiring exact c'tor arguments, TID not supporting shared, the thread-local storage/GC issue, and maybe no function overloading with template parameters bugs. The TLS issue is already known.) These have a lot higher a probability of getting fixed if you file them as bug reports (see http://d.puremagic.com/issues/ ). Better yet, if yo know how to fix it, you can submit a pull request to the DProgrammingLanguage Github page. Other things you mention are design decisions that are the result of carefully considered tradeoffs. These include structs not having an identity, lack of implicit c'tors, and shared. These are tradeoffs that may not be the best for your situation, but are not unforced errors. As far as assert, maybe there should be a compiler switch that makes all asserts behave the way assert(0) does in release mode: Simply issue the HLT instruction and use a debugger to figure out what went wrong. However, I think the current behavior of assert is the right default behavior because it gives clear hints as to what went wrong (and a stack trace on newer releases) even if you're not running in a debugger. Associative array invariance may be fixable now using reference counting. This issue has been in the back of my mind for a long time. Thanks for bringing it back to the front, and maybe it's worth fixing.
Aug 27 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
dsimcha:

Some of the things you mention are definitely bugs. (I'd call emplace requiring
exact c'tor arguments, TID not supporting shared, the thread-local storage/GC
issue, and maybe no function overloading with template parameters bugs.  The
TLS issue is already known.)  These have a lot higher a probability of getting
fixed if you file them as bug reports<

Otherwise, are you able and willing to add those to Bugzilla yourself? Bye, bearophile
Aug 28 2011
next sibling parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
I hoped for a little bit more feedback about the article itself.
Especially about the move constructor I suggested. Does anyone see a 
need for this, or is it just me?

-- 
Kind Regards
Benjamin Thaut
Aug 29 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/29/2011 2:22 PM, Jonathan M Davis wrote:
 Certainly, for the common case, adding move constructors is a needless
 complication, and I'd _very_ leery of the ramifications of the compiler not
 being able to rely on a move having the bits stay absolutely identical (and a
 move constructor would make it possible for the struct's state to change
 completely instead of really being a move). It's not necessarily completely
 unreasonable, but you appear to have found what I would expect to be a _very_
 abnormal use-case.

Andrei and I have talked about adding move constructors, but I agree with you that it really seems to be a tar pit we'd really like to avoid. C++ has a lot of subtle problems caused by supporting this, not the least of which is efficiency problems.
Aug 29 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/29/11 4:36 PM, Walter Bright wrote:
 On 8/29/2011 2:22 PM, Jonathan M Davis wrote:
 Certainly, for the common case, adding move constructors is a needless
 complication, and I'd _very_ leery of the ramifications of the
 compiler not
 being able to rely on a move having the bits stay absolutely identical
 (and a
 move constructor would make it possible for the struct's state to change
 completely instead of really being a move). It's not necessarily
 completely
 unreasonable, but you appear to have found what I would expect to be a
 _very_
 abnormal use-case.

Andrei and I have talked about adding move constructors, but I agree with you that it really seems to be a tar pit we'd really like to avoid. C++ has a lot of subtle problems caused by supporting this, not the least of which is efficiency problems.

The language semantics make move construction unnecessary. Values are moveable as bits through memory. I think the article is a bit confused on this particular matter. Only objects with value semantics are freely moveable, so they have no direct interaction with the garbage collector. What they might want to do is to hold a pointer/reference _inside_ of them and deregister that pointer with the garbage collector with the destructor. Due to the indirection, it doesn't matter where the object is in memory. Andrei
Aug 29 2011
parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
Am 30.08.2011 02:56, schrieb Andrei Alexandrescu:
 On 8/29/11 4:36 PM, Walter Bright wrote:
 On 8/29/2011 2:22 PM, Jonathan M Davis wrote:
 Certainly, for the common case, adding move constructors is a needless
 complication, and I'd _very_ leery of the ramifications of the
 compiler not
 being able to rely on a move having the bits stay absolutely identical
 (and a
 move constructor would make it possible for the struct's state to change
 completely instead of really being a move). It's not necessarily
 completely
 unreasonable, but you appear to have found what I would expect to be a
 _very_
 abnormal use-case.

Andrei and I have talked about adding move constructors, but I agree with you that it really seems to be a tar pit we'd really like to avoid. C++ has a lot of subtle problems caused by supporting this, not the least of which is efficiency problems.

The language semantics make move construction unnecessary. Values are moveable as bits through memory. I think the article is a bit confused on this particular matter. Only objects with value semantics are freely moveable, so they have no direct interaction with the garbage collector. What they might want to do is to hold a pointer/reference _inside_ of them and deregister that pointer with the garbage collector with the destructor. Due to the indirection, it doesn't matter where the object is in memory. Andrei

I don't see implementing a GC as that of a abnormal use case. Especially given the fact that D is a garbage collected language and could benefit a lot from features that make implementing a GC easier. In thise special case the discussed struct would be a wrapper for every reference on the stack, so the references can be tracked by the GC and changed if neccessary. Adding a level of indirection to every reference would greatly impact performance because it would most likely add yet another cache miss when accessing a reference. I'm very well aware of D's concept of structs. But sometimes this concept is very bad for performance, that is what I wanted to point out. Adding a move constructor which most of the structs won't even use, should be less of a performance impact, then adding another level of indirection. -- Kind Regards Benjamin Thaut
Aug 29 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/30/11 12:45 AM, Benjamin Thaut wrote:
 Am 30.08.2011 02:56, schrieb Andrei Alexandrescu:
 On 8/29/11 4:36 PM, Walter Bright wrote:
 On 8/29/2011 2:22 PM, Jonathan M Davis wrote:
 Certainly, for the common case, adding move constructors is a needless
 complication, and I'd _very_ leery of the ramifications of the
 compiler not
 being able to rely on a move having the bits stay absolutely identical
 (and a
 move constructor would make it possible for the struct's state to
 change
 completely instead of really being a move). It's not necessarily
 completely
 unreasonable, but you appear to have found what I would expect to be a
 _very_
 abnormal use-case.

Andrei and I have talked about adding move constructors, but I agree with you that it really seems to be a tar pit we'd really like to avoid. C++ has a lot of subtle problems caused by supporting this, not the least of which is efficiency problems.

The language semantics make move construction unnecessary. Values are moveable as bits through memory. I think the article is a bit confused on this particular matter. Only objects with value semantics are freely moveable, so they have no direct interaction with the garbage collector. What they might want to do is to hold a pointer/reference _inside_ of them and deregister that pointer with the garbage collector with the destructor. Due to the indirection, it doesn't matter where the object is in memory. Andrei

I don't see implementing a GC as that of a abnormal use case.

Implementing a GC is an exceedingly rare privilege.
 Especially
 given the fact that D is a garbage collected language and could benefit
 a lot from features that make implementing a GC easier.

I don't believe D should be in the business of adding features that make implementing a GC easier. Such a task is extremely specialized; if the language allows it, that's about enough.
 In thise special
 case the discussed struct would be a wrapper for every reference on the
 stack, so the references can be tracked by the GC and changed if
 neccessary. Adding a level of indirection to every reference would
 greatly impact performance because it would most likely add yet another
 cache miss when accessing a reference. I'm very well aware of D's
 concept of structs. But sometimes this concept is very bad for
 performance, that is what I wanted to point out. Adding a move
 constructor which most of the structs won't even use, should be less of
 a performance impact, then adding another level of indirection.

Clearly adding an extra level of indirection would be harmful, no two ways about it. But essentially the object model is what it is: there are value types that move, and there are reference types that don't. Deal with it. If you need to implement a garbage collector, you can't do it with move hooks because they're not provided. In a subtle way it's a given, although I totally understand how this or that hook would make your work easier. I don't find the complaint valid at all. Andrei
Aug 29 2011
parent reply Benjamin Thaut <code benjamin-thaut.de> writes:
Am 30.08.2011 08:00, schrieb Andrei Alexandrescu:
 On 8/30/11 12:45 AM, Benjamin Thaut wrote:
 Am 30.08.2011 02:56, schrieb Andrei Alexandrescu:
 On 8/29/11 4:36 PM, Walter Bright wrote:
 On 8/29/2011 2:22 PM, Jonathan M Davis wrote:
 Certainly, for the common case, adding move constructors is a needless
 complication, and I'd _very_ leery of the ramifications of the
 compiler not
 being able to rely on a move having the bits stay absolutely identical
 (and a
 move constructor would make it possible for the struct's state to
 change
 completely instead of really being a move). It's not necessarily
 completely
 unreasonable, but you appear to have found what I would expect to be a
 _very_
 abnormal use-case.

Andrei and I have talked about adding move constructors, but I agree with you that it really seems to be a tar pit we'd really like to avoid. C++ has a lot of subtle problems caused by supporting this, not the least of which is efficiency problems.

The language semantics make move construction unnecessary. Values are moveable as bits through memory. I think the article is a bit confused on this particular matter. Only objects with value semantics are freely moveable, so they have no direct interaction with the garbage collector. What they might want to do is to hold a pointer/reference _inside_ of them and deregister that pointer with the garbage collector with the destructor. Due to the indirection, it doesn't matter where the object is in memory. Andrei

I don't see implementing a GC as that of a abnormal use case.

Implementing a GC is an exceedingly rare privilege.
 Especially
 given the fact that D is a garbage collected language and could benefit
 a lot from features that make implementing a GC easier.

I don't believe D should be in the business of adding features that make implementing a GC easier. Such a task is extremely specialized; if the language allows it, that's about enough.
 In thise special
 case the discussed struct would be a wrapper for every reference on the
 stack, so the references can be tracked by the GC and changed if
 neccessary. Adding a level of indirection to every reference would
 greatly impact performance because it would most likely add yet another
 cache miss when accessing a reference. I'm very well aware of D's
 concept of structs. But sometimes this concept is very bad for
 performance, that is what I wanted to point out. Adding a move
 constructor which most of the structs won't even use, should be less of
 a performance impact, then adding another level of indirection.

Clearly adding an extra level of indirection would be harmful, no two ways about it. But essentially the object model is what it is: there are value types that move, and there are reference types that don't. Deal with it. If you need to implement a garbage collector, you can't do it with move hooks because they're not provided. In a subtle way it's a given, although I totally understand how this or that hook would make your work easier. I don't find the complaint valid at all. Andrei

My problem currenlty mostly is, that the current GC takes way more time then the usual 5% slowdown that gets mentioned with most GCs. Thats why I would prefer adding features that would make implementing GCs a) easier b) would actually allow do implement a GC that is not a Mark & Sweep c) faster because they won't have to scan all memory searching for a pointer Currently there is no way to track the references or pointers on the stack because the language does not include such a feature, nor can it be build with any of the language provided mechanisms. But maybe its just my point of view on this. In the field I'm mostly active in (3d games) performance is everything. Especially on the consoles. Most programmers even sacrifice most c++ features on the consoles (exceptions, RTTI, virtual functions to some extend) just to get more performance out of their game. -- Kind Regards Benjamin Thaut
Aug 31 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/31/2011 9:58 AM, Benjamin Thaut wrote:
 Currently there is no way to track the references or pointers on the stack
 because the language does not include such a feature, nor can it be build with
 any of the language provided mechanisms.

The trouble with precise GC is that all the type info consumes a large amount of memory.
 But maybe its just my point of view on this. In the field I'm mostly active in
 (3d games) performance is everything. Especially on the consoles. Most
 programmers even sacrifice most c++ features on the consoles (exceptions, RTTI,
 virtual functions to some extend) just to get more performance out of their
game.

It's fairly straightforward to do the GC collection cycles during slack time, and avoid it during time critical sections. And note that if you've got hard real time constraints, you cannot even use malloc/free, as they do not run in bounded time.
Aug 31 2011
next sibling parent Mehrdad <wfunction hotmail.com> writes:
On 8/31/2011 10:23 PM, Walter Bright wrote:
 On 8/31/2011 9:58 AM, Benjamin Thaut wrote:
 Currently there is no way to track the references or pointers on the 
 stack
 because the language does not include such a feature, nor can it be 
 build with
 any of the language provided mechanisms.

The trouble with precise GC is that all the type info consumes a large amount of memory.

Sep 01 2011
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/01/2011 12:23 AM, Walter Bright wrote:
 On 8/31/2011 9:58 AM, Benjamin Thaut wrote:
 Currently there is no way to track the references or pointers on the
 stack
 because the language does not include such a feature, nor can it be
 build with
 any of the language provided mechanisms.

The trouble with precise GC is that all the type info consumes a large amount of memory.

I think our community will be rid of a major hurdle once we get past the debate on whether precise GC is necessary. Precise GC is necessary, there's no two ways about it. We should worry about implementing, not debating, it. Andrei
Sep 01 2011
next sibling parent dsimcha <dsimcha yahoo.com> writes:
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
 I think our community will be rid of a major hurdle once we get past the
 debate on whether precise GC is necessary. Precise GC is necessary,
 there's no two ways about it. We should worry about implementing, not
 debating, it.
 Andrei

while(1) { vote++; } Needless to say, I'm quite frustrated that I implemented precise heap scanning almost two **years** ago and it's gone basically nowhere. Admittedly there were some unresolved plumbing issues with regard to getting the relevant type info to the GC from the new operator, etc. but it actually worked for memory allocated via GC.malloc and there were tests to back it up.
Sep 01 2011
prev sibling parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 01-09-2011 16:42, Andrei Alexandrescu wrote:
 On 09/01/2011 12:23 AM, Walter Bright wrote:
 On 8/31/2011 9:58 AM, Benjamin Thaut wrote:
 Currently there is no way to track the references or pointers on the
 stack
 because the language does not include such a feature, nor can it be
 build with
 any of the language provided mechanisms.

The trouble with precise GC is that all the type info consumes a large amount of memory.

I think our community will be rid of a major hurdle once we get past the debate on whether precise GC is necessary. Precise GC is necessary, there's no two ways about it. We should worry about implementing, not debating, it. Andrei

And honestly, the memory footprint for the type info is negligible with the amount of memory available today, especially as D is going towards x86-64 support. - Alex
Sep 01 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, August 29, 2011 13:35 Benjamin Thaut wrote:
 I hoped for a little bit more feedback about the article itself.
 Especially about the move constructor I suggested. Does anyone see a
 need for this, or is it just me?

Honestly, I find the fact that you're writing code which relies on the address of a variable on the stack a bit scary. Normally, that is a _bad_ idea. Now, you're obviously doing something quite abnormal, so it may be a good idea in your case, but you're definitely not doing something which your average programmer is going to need to do. And the fact that structs can be moved by having their bits copied around is a definite boon for efficiency. Adding move constructors would definitely complicate things. If there were enough use cases for them, then they may be worth adding, but at this point, the compiler definitely relies on the fact that it can move a struct without affecting it, so any code which relies on a struct _not_ moving is likely to be broken. The ramifications of adding move constructors are likely far from trivial. Personally, I'd argue that it doesn't make any more sense to expect that a struct's location have _anything_ to do with its value, and that if you want to rely on its location, then you need to put it in a location that you can rely on. If anything, I'd argue that your structs should just have a variable identifying them if you want to have them be uniquely identifiable, but I don't really understand what you're doing. Certainly, for the common case, adding move constructors is a needless complication, and I'd _very_ leery of the ramifications of the compiler not being able to rely on a move having the bits stay absolutely identical (and a move constructor would make it possible for the struct's state to change completely instead of really being a move). It's not necessarily completely unreasonable, but you appear to have found what I would expect to be a _very_ abnormal use-case. - Jonathan M Davis
Aug 29 2011
prev sibling next sibling parent Josh Simmons <simmons.44 gmail.com> writes:
On Thu, Sep 1, 2011 at 3:23 PM, Walter Bright
<newshound2 digitalmars.com> wrote:
 And note that if you've got hard real time constraints, you cannot even use
 malloc/free, as they do not run in bounded time.

They're generally avoided in game code anyway because they're slow. Games don't have hard real time constraints though in the strictest sense, but you have a fixed budget with which to work all game logic and rendering having the GC kick in at the wrong time or run a bit longer than expected can lead to very nasty frame drops. You really need to be able to say when you want the GC to run, and how long you're willing to give it to execute.
Aug 31 2011
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
There are soft realtime GCs like you describe, but I believe they're all inc=
remental. I don't know that approach is compatible with D.=20

Sent from my iPhone

On Aug 31, 2011, at 10:35 PM, Josh Simmons <simmons.44 gmail.com> wrote:

 On Thu, Sep 1, 2011 at 3:23 PM, Walter Bright
 <newshound2 digitalmars.com> wrote:
=20
 And note that if you've got hard real time constraints, you cannot even u=


 malloc/free, as they do not run in bounded time.
=20

They're generally avoided in game code anyway because they're slow. =20 Games don't have hard real time constraints though in the strictest sense, but you have a fixed budget with which to work all game logic and rendering having the GC kick in at the wrong time or run a bit longer than expected can lead to very nasty frame drops. You really need to be able to say when you want the GC to run, and how long you're willing to give it to execute.

Sep 01 2011
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
Yup. I want to revisit CDGC to see if it's up to snuff as the default GC. It=
 already supports precise scanning, so perhaps the rest can be sorted via li=
brary code: create!T(...)

Sent from my iPhone

On Sep 1, 2011, at 7:56 AM, dsimcha <dsimcha yahoo.com> wrote:

 =3D=3D Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
 I think our community will be rid of a major hurdle once we get past the
 debate on whether precise GC is necessary. Precise GC is necessary,
 there's no two ways about it. We should worry about implementing, not
 debating, it.
 Andrei

while(1) { vote++; } =20 Needless to say, I'm quite frustrated that I implemented precise heap scan=

 almost two **years** ago and it's gone basically nowhere.  Admittedly ther=

 some unresolved plumbing issues with regard to getting the relevant type i=

 the GC from the new operator, etc. but it actually worked for memory alloc=

 GC.malloc and there were tests to back it up.

Sep 01 2011
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 01 Sep 2011 11:46:32 -0400, Sean Kelly <sean invisibleduck.org> wrote:
 Yup. I want to revisit CDGC to see if it's up to snuff as the default GC. It
already supports precise scanning, so perhaps the rest can be sorted via
library code: create!T(...)

 Sent from my iPhone

Default on *nix you mean, as CDGC sadly doesn't support windows.
Sep 01 2011
prev sibling next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Thu, 01 Sep 2011 10:56:27 -0400, dsimcha <dsimcha yahoo.com> wrote:

 == Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s
 I think our community will be rid of a major hurdle once we get past the
 debate on whether precise GC is necessary. Precise GC is necessary,
 there's no two ways about it. We should worry about implementing, not
 debating, it.
 Andrei

while(1) { vote++; } Needless to say, I'm quite frustrated that I implemented precise heap scanning almost two **years** ago and it's gone basically nowhere. Admittedly there were some unresolved plumbing issues with regard to getting the relevant type info to the GC from the new operator, etc. but it actually worked for memory allocated via GC.malloc and there were tests to back it up.

Make that while(1) { vote +=2 ; }
Sep 01 2011
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
On Sep 1, 2011, at 7:57 PM, Robert Jacques wrote:

 On Thu, 01 Sep 2011 11:46:32 -0400, Sean Kelly =

 Yup. I want to revisit CDGC to see if it's up to snuff as the default =


sorted via library code: create!T(...)
=20
 Default on *nix you mean, as CDGC sadly doesn't support windows.

It should. It just won't be able to use its fork-based speedup. That = should still have it run on par with the GC we use today. If there are = any actual problems running on Windows, they shouldn't be too hard to = fix.=
Sep 02 2011
prev sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Fri, 02 Sep 2011 13:34:12 -0400, Sean Kelly <sean invisibleduck.org> wrote:

 On Sep 1, 2011, at 7:57 PM, Robert Jacques wrote:

 On Thu, 01 Sep 2011 11:46:32 -0400, Sean Kelly <sean invisibleduck.org> wrote:
 Yup. I want to revisit CDGC to see if it's up to snuff as the default GC. It
already supports precise scanning, so perhaps the rest can be sorted via
library code: create!T(...)

Default on *nix you mean, as CDGC sadly doesn't support windows.

It should. It just won't be able to use its fork-based speedup. That should still have it run on par with the GC we use today. If there are any actual problems running on Windows, they shouldn't be too hard to fix.

Well, it would be a concurrent GC on Linux and (after patching) parallel(?) GC on Windows. So, I take your point that a lot of code could be re-used/shared between the two OSes.
Sep 02 2011
prev sibling next sibling parent reply Mehrdad <wfunction hotmail.com> writes:
On 8/27/2011 10:14 AM, Benjamin Thaut wrote:
 After having used the D 2.0 programming language for a year now and 
 having completed 3 projects with it, I wrote a small article about the 
 problems I had with the D 2.0 programming language and what 
 suggestions I have to improve it.

 http://3d.benjamin-thaut.de/?p=18

 Comments and criticism welcome

 "This transitiv[it]y basically kills you everywhere."

I feel like you hit the nail on the head. I feel the same way about const. Transitivity is beautiful on the outside, but I can never actually get it working, so I just make everything non-const. I have to sometimes do this even in Phobos itself, because the compiler complains about something random caused by transitivity. I also fail to see what /problem/ it's trying to solve. The DigitalMars website simply states: "With transitivity, there is no way to have a const pointer to mutable int." But... so what? Maybe it should actually explain the benefit, since I can't figure it out on my own. (The related discussion on "head-const" and "tail-const" seems completely irrelevant to the topic." C++'s non-transitivity seems to be quite type-safe, even if unintuitive to the beginner (which I don't think it is). I *never* ran into issues with it. *On the bright side*, I LOVE immutable. It's one of the best features of D, IMO. (Or at least it would be, if only it /wasn't/ transitive.) I don't like the way C++ mixes the idea of "this never mutates" versus "YOU can't mutate this object", and I feel like D was really smart in making the distinction between the two. Related suggestion: All methods that return /new/ strings should return *mutable* arrays. There's really no reason (that I can think of) to not do this: if you see something returning a mutable array, you _know_ it's a new array (unless otherwise documented), so you _know_ it's safe to cast it to immutable if needed. It doesn't work the other way around, though.
Aug 27 2011
next sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Mehrdad" <wfunction hotmail.com> wrote in message 
news:j3beu2$25a8$1 digitalmars.com...
 Related suggestion: All methods that return /new/ strings should return 
 *mutable* arrays. There's really no reason (that I can think of) to not do 
 this: if you see something returning a mutable array, you _know_ it's a 
 new array (unless otherwise documented), so you _know_ it's safe to cast 
 it to immutable if needed. It doesn't work the other way around, though.

Since a few days ago, mutable strings returned from strongly pure functions can be implicitly converted to immutable ones, so a cast won't be needed any more.
Aug 27 2011
parent reply dsimcha <dsimcha yahoo.com> writes:
On 8/27/2011 3:47 PM, Daniel Murphy wrote:
 "Mehrdad"<wfunction hotmail.com>  wrote in message
 news:j3beu2$25a8$1 digitalmars.com...
 Related suggestion: All methods that return /new/ strings should return
 *mutable* arrays. There's really no reason (that I can think of) to not do
 this: if you see something returning a mutable array, you _know_ it's a
 new array (unless otherwise documented), so you _know_ it's safe to cast
 it to immutable if needed. It doesn't work the other way around, though.

Since a few days ago, mutable strings returned from strongly pure functions can be implicitly converted to immutable ones, so a cast won't be needed any more.

Does the same apply to all arrays of primitives?
Aug 27 2011
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"dsimcha" <dsimcha yahoo.com> wrote in message 
news:j3bk94$2e72$1 digitalmars.com...
 Since a few days ago, mutable strings returned from strongly pure 
 functions
 can be implicitly converted to immutable ones, so a cast won't be needed 
 any
 more.

Does the same apply to all arrays of primitives?

To all types. Arrays, AAs, classes etc.
Aug 28 2011
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Mehrdad:

 "With transitivity, there is no way to have a const pointer to mutable int."
 
 But... so what? Maybe it should actually explain the benefit, since I 
 can't figure it out on my own.

D wants both mutable data and (strongly) pure functions. How do you bridge such two worlds? If you have mutable data and you want to pass it to a pure function, you need a way to say this data structure will not change, nor any data it refers to. I think the D transitive const is the simpler way to do this.
 C++'s non-transitivity seems to be quite type-safe, even if unintuitive 
 to the beginner (which I don't think it is). I *never* ran into issues 
 with it.

The C++ compiler doesn't offer means to enforce pure functions. In my opinion it's possible to add a C++-style const to D too, but this further increases the complexity of D, it cannot be used for purity, and it can't be used for compiler optimizations, you are allowed to safely cast it away when you want, it's just a convention, as in C++. But maybe it's useful anyway because most times you try to mutate the first level of a data structure, and such shallow const is enough to catch such unintentional mutation bug. Bye, bearophile
Aug 27 2011
parent reply =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= <xtzgzorex gmail.com> writes:
On 28-08-2011 01:05, bearophile wrote:
 Mehrdad:

 "With transitivity, there is no way to have a const pointer to mutable int."

 But... so what? Maybe it should actually explain the benefit, since I
 can't figure it out on my own.

D wants both mutable data and (strongly) pure functions. How do you bridge such two worlds? If you have mutable data and you want to pass it to a pure function, you need a way to say this data structure will not change, nor any data it refers to. I think the D transitive const is the simpler way to do this.
 C++'s non-transitivity seems to be quite type-safe, even if unintuitive
 to the beginner (which I don't think it is). I *never* ran into issues
 with it.

The C++ compiler doesn't offer means to enforce pure functions. In my opinion it's possible to add a C++-style const to D too, but this further increases the complexity of D, it cannot be used for purity, and it can't be used for compiler optimizations, you are allowed to safely cast it away when you want, it's just a convention, as in C++. But maybe it's useful anyway because most times you try to mutate the first level of a data structure, and such shallow const is enough to catch such unintentional mutation bug. Bye, bearophile

const_cast is the root of all evil. I really don't want to see it in D. - Alex
Aug 28 2011
parent reply David Nadlinger <see klickverbot.at> writes:
On 8/28/11 8:54 PM, Alex Rønne Petersen wrote:
 const_cast is the root of all evil. I really don't want to see it in D.

 - Alex

It is already in D, and in an, in my personal opinion, much worse way: You can just cast away const/immutable with cast(). What do you propose for the situations where you need to cast away const? (Yes you'll find yourself in one of them from time to time in the real world, e.g. when dealing with legacy/C code…) I know that this is not the general consensus, but I very much like the C++ casting operators, because you can quickly get a rough idea what is going on when you see a cast in the code, whereas for D, cast() be anything between a perfectly harmless downcast (if checking for null, obviously), changing the storage class (const/immutable/shared), or causing the bytes stored to be interpreted in a completely different way! David
Aug 28 2011
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/28/2011 12:44 PM, David Nadlinger wrote:
 It is already in D, and in an, in my personal opinion, much worse way: You can
 just cast away const/immutable with cast().

True, but such is explicitly undefined behavior, and is not allowed in safe mode.
 What do you propose for the situations where you need to cast away const? (Yes
 you'll find yourself in one of them from time to time in the real world, e.g.
 when dealing with legacy/C code…)

That's why D does allow this, in a user visible manner, rather than forcing one to do it in a backdoor manner (like using inline asm).
 I know that this is not the general consensus, but I very much like the C++
 casting operators, because you can quickly get a rough idea what is going on
 when you see a cast in the code, whereas for D, cast() be anything between a
 perfectly harmless downcast (if checking for null, obviously), changing the
 storage class (const/immutable/shared), or causing the bytes stored to be
 interpreted in a completely different way!

To cast away const, use: cast()expr i.e. there is a special syntax for it.
Aug 28 2011
parent David Nadlinger <see klickverbot.at> writes:
On 8/28/11 10:17 PM, Walter Bright wrote:
 On 8/28/2011 12:44 PM, David Nadlinger wrote:
 I know that this is not the general consensus, but I very much like
 the C++
 casting operators, because you can quickly get a rough idea what is
 going on
 when you see a cast in the code, whereas for D, cast() be anything
 between a
 perfectly harmless downcast (if checking for null, obviously),
 changing the
 storage class (const/immutable/shared), or causing the bytes stored to be
 interpreted in a completely different way!

To cast away const, use: cast()expr i.e. there is a special syntax for it.

I know about the »it's not a bug, it's a feature« cast() syntax officially added some three (?) months ago, but it should be noted that it also removes shared from the type (incidentally, const_cast removes volatile as well). Personally, I think that being explicit about the type of operation one intends to perform is a good thing, especially if you are about to subvert the type system. Still, I feel using my own custom set of casting templates would be too confusing for other people reading my code – would anybody else be interested in adding »restricted« casting templates to Phobos? David
Aug 28 2011
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 08/28/2011 02:44 PM, David Nadlinger wrote:
 On 8/28/11 8:54 PM, Alex Rønne Petersen wrote:
 const_cast is the root of all evil. I really don't want to see it in D.

 - Alex

It is already in D, and in an, in my personal opinion, much worse way: You can just cast away const/immutable with cast(). What do you propose for the situations where you need to cast away const? (Yes you'll find yourself in one of them from time to time in the real world, e.g. when dealing with legacy/C code…) I know that this is not the general consensus, but I very much like the C++ casting operators, because you can quickly get a rough idea what is going on when you see a cast in the code, whereas for D, cast() be anything between a perfectly harmless downcast (if checking for null, obviously), changing the storage class (const/immutable/shared), or causing the bytes stored to be interpreted in a completely different way! David

It is quite easy to define C++-like cast operators as D functions. If there's enough demand for that, we may include such in the standard library. Andrei
Aug 28 2011
next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
On 8/28/2011 4:52 PM, Andrei Alexandrescu wrote:
 It is quite easy to define C++-like cast operators as D functions. If
 there's enough demand for that, we may include such in the standard
 library.

 Andrei

I think we should define at least the following and probably put them in std.conv, since these would add real value over the cast operator, the first in terms of straightforwardness and readability and the second in terms of error checking: reinterpretCast: Reinterprets the bit pattern at a given address as some other type. This should be broadened from C++ to allow reinterpretCasting from any type to any type. For example: // Fancy way of making a floating point number negative. float f = 5; auto i = reinterpretCast!int(f); // Flip the sign bit. i &= ~(1 << 31); f = reinterpretCast!float(i); dynamicCast: Cast a class to another. This should throw something derived from Error (not Exception) on failure instead of just returning null. If you want null, just use the cast operator. Maybe we should change its name, though. How about checkedCast or downCast?
Aug 28 2011
parent reply Mafi <mafi example.org> writes:
Am 28.08.2011 23:13, schrieb dsimcha:
 On 8/28/2011 4:52 PM, Andrei Alexandrescu wrote:
 It is quite easy to define C++-like cast operators as D functions. If
 there's enough demand for that, we may include such in the standard
 library.

 Andrei

I think we should define at least the following and probably put them in std.conv, since these would add real value over the cast operator, the first in terms of straightforwardness and readability and the second in terms of error checking: reinterpretCast: Reinterprets the bit pattern at a given address as some other type. This should be broadened from C++ to allow reinterpretCasting from any type to any type. For example: // Fancy way of making a floating point number negative. float f = 5; auto i = reinterpretCast!int(f); // Flip the sign bit. i &= ~(1 << 31); f = reinterpretCast!float(i); dynamicCast: Cast a class to another. This should throw something derived from Error (not Exception) on failure instead of just returning null. If you want null, just use the cast operator. Maybe we should change its name, though. How about checkedCast or downCast?

I think, to!someClass(x) works like you want dynamic cast to work.
Aug 28 2011
parent reply dsimcha <dsimcha yahoo.com> writes:
On 8/28/2011 5:18 PM, Mafi wrote:
 dynamicCast: Cast a class to another. This should throw something
 derived from Error (not Exception) on failure instead of just returning
 null. If you want null, just use the cast operator. Maybe we should
 change its name, though. How about checkedCast or downCast?

I think, to!someClass(x) works like you want dynamic cast to work.

(Slaps self in forehead.) You're right, I forgot about that. Never mind.
Aug 28 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 08/28/2011 04:31 PM, dsimcha wrote:
 On 8/28/2011 5:18 PM, Mafi wrote:
 dynamicCast: Cast a class to another. This should throw something
 derived from Error (not Exception) on failure instead of just returning
 null. If you want null, just use the cast operator. Maybe we should
 change its name, though. How about checkedCast or downCast?

I think, to!someClass(x) works like you want dynamic cast to work.

(Slaps self in forehead.) You're right, I forgot about that. Never mind.

I think such an addition would be worthwhile. We'd only need std.conv.reinterpretCast as that's a distinct way to convert types than to!T. The function would only work if the source and target types have the same size. Some overloads of it would be safe (e.g. integral or floating point target) whereas others won't (e.g. those that forge pointers or references). Note that reinterpretCast would support conversions not covered by cast, e.g. converting a chunk of memory to a class object or one struct to another struct. Andrei
Aug 28 2011
parent reply Mehrdad <wfunction hotmail.com> writes:
On 8/28/2011 2:49 PM, Andrei Alexandrescu wrote:
 On 08/28/2011 04:31 PM, dsimcha wrote:
 On 8/28/2011 5:18 PM, Mafi wrote:
 dynamicCast: Cast a class to another. This should throw something
 derived from Error (not Exception) on failure instead of just 
 returning
 null. If you want null, just use the cast operator. Maybe we should
 change its name, though. How about checkedCast or downCast?

I think, to!someClass(x) works like you want dynamic cast to work.

(Slaps self in forehead.) You're right, I forgot about that. Never mind.

I think such an addition would be worthwhile. We'd only need std.conv.reinterpretCast as that's a distinct way to convert types than to!T. The function would only work if the source and target types have the same size. Some overloads of it would be safe (e.g. integral or floating point target) whereas others won't (e.g. those that forge pointers or references). Note that reinterpretCast would support conversions not covered by cast, e.g. converting a chunk of memory to a class object or one struct to another struct. Andrei

type "reinterpretCast" in my source code (let alone /import/ std.conv, just for a cast) unless the IDE was the one doing the typing.
Aug 31 2011
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/01/2011 12:06 AM, Mehrdad wrote:
 On 8/28/2011 2:49 PM, Andrei Alexandrescu wrote:
 On 08/28/2011 04:31 PM, dsimcha wrote:
 On 8/28/2011 5:18 PM, Mafi wrote:
 dynamicCast: Cast a class to another. This should throw something
 derived from Error (not Exception) on failure instead of just
 returning
 null. If you want null, just use the cast operator. Maybe we should
 change its name, though. How about checkedCast or downCast?

I think, to!someClass(x) works like you want dynamic cast to work.

(Slaps self in forehead.) You're right, I forgot about that. Never mind.

I think such an addition would be worthwhile. We'd only need std.conv.reinterpretCast as that's a distinct way to convert types than to!T. The function would only work if the source and target types have the same size. Some overloads of it would be safe (e.g. integral or floating point target) whereas others won't (e.g. those that forge pointers or references). Note that reinterpretCast would support conversions not covered by cast, e.g. converting a chunk of memory to a class object or one struct to another struct. Andrei

type "reinterpretCast" in my source code (let alone /import/ std.conv, just for a cast) unless the IDE was the one doing the typing.

Verboseness would be the last problem of a program needing many instances of reinterpretCast. Andrei
Sep 01 2011
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 It is quite easy to define C++-like cast operators as D functions. If 
 there's enough demand for that, we may include such in the standard library.

I'd like this one in Phobos: http://d.puremagic.com/issues/show_bug.cgi?id=5559 Having it in Phobos is hopefully better than creating your own one from scratch when the need arises. Bye, bearophile
Aug 28 2011
prev sibling parent reply David Nadlinger <see klickverbot.at> writes:
On 8/28/11 10:52 PM, Andrei Alexandrescu wrote:
 It is quite easy to define C++-like cast operators as D functions. If
 there's enough demand for that, we may include such in the standard
 library.

I hope this finally goes through, there still seem to be some – hurricane-related, probably – stability issues with the server. Anyway, a library solution is definitely what I am thinking about, especially since it's just a matter of a template with a fitting constraint. But as said in my other post (that also took quite a few attempts to post), I think such casting templates would make most sense if standardized, i.e. included with Phobos. David
Aug 28 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/28/2011 3:56 PM, David Nadlinger wrote:
 I hope this finally goes through, there still seem to be some –
 hurricane-related, probably – stability issues with the server.

The only stability issue was the massive power outage. Jan got it back up running using a generator. Jan has always done an excellent job taking care of the server, and I am very satisfied.
Aug 28 2011
parent reply David Nadlinger <see klickverbot.at> writes:
On 8/29/11 1:27 AM, Walter Bright wrote:
 On 8/28/2011 3:56 PM, David Nadlinger wrote:
 I hope this finally goes through, there still seem to be some –
 hurricane-related, probably – stability issues with the server.

The only stability issue was the massive power outage. Jan got it back up running using a generator. Jan has always done an excellent job taking care of the server, and I am very satisfied.

Yes – I didn't mean to discredit anyone, but I were definitely having problems reaching the server during the last few hours. I didn't look at a traceroute though, it could well be that some carrier was at fault. David
Aug 28 2011
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/28/2011 4:34 PM, David Nadlinger wrote:
 On 8/29/11 1:27 AM, Walter Bright wrote:
 On 8/28/2011 3:56 PM, David Nadlinger wrote:
 I hope this finally goes through, there still seem to be some –
 hurricane-related, probably – stability issues with the server.

The only stability issue was the massive power outage. Jan got it back up running using a generator. Jan has always done an excellent job taking care of the server, and I am very satisfied.

Yes – I didn't mean to discredit anyone, but I were definitely having problems reaching the server during the last few hours. I didn't look at a traceroute though, it could well be that some carrier was at fault.

It was down for 4 hours. Jan told me that he didn't care to try to get the generator engaged in total darkness in the middle of a hurricane. I don't blame him, I wouldn't either. Messing with generators can be dangerous, and getting hit with flying debris even worse.
Aug 28 2011
prev sibling parent Kagamin <spam here.lot> writes:
Mehrdad Wrote:

 I feel like you hit the nail on the head. I feel the same way about const.
 
 Transitivity is beautiful on the outside, but I can never actually get 
 it working, so I just make everything non-const. I have to sometimes do 
 this even in Phobos itself, because the compiler complains about 
 something random caused by transitivity.
 I also fail to see what /problem/ it's trying to solve. The DigitalMars 
 website simply states:
 
 "With transitivity, there is no way to have a const pointer to mutable int."
 
 But... so what? Maybe it should actually explain the benefit, since I 
 can't figure it out on my own. (The related discussion on "head-const" 
 and "tail-const" seems completely irrelevant to the topic."
 
 C++'s non-transitivity seems to be quite type-safe, even if unintuitive 
 to the beginner (which I don't think it is). I *never* ran into issues 
 with it.

In C I had to cast away const because constness is built into the struct itself - if you want the struct to be accessed as readonly. In D transitive const is transparent - you can have the save structure both readonly and mutable.
Aug 30 2011
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 08/27/2011 12:14 PM, Benjamin Thaut wrote:
 After having used the D 2.0 programming language for a year now and
 having completed 3 projects with it, I wrote a small article about the
 problems I had with the D 2.0 programming language and what suggestions
 I have to improve it.

 http://3d.benjamin-thaut.de/?p=18

 Comments and criticism welcome

Reddit discussion has turned to tuples: http://www.reddit.com/r/programming/comments/jwkvx/suggestions_for_the_d_20_programming_language/ Andrei
Aug 28 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 Reddit discussion has turned to tuples:

boost::tuples::tie is ugly compared to the syntax proposed in that pull request.
 They work well except when expanding to multiple variables,

There are two more places where it's handy to expand tuples: function signatures and foreach :-) But I don't know what good syntax to use yet, suggestions welcome. Is Kenji Hara interested? Bye, bearophile
Aug 28 2011
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
One of the comments written by Walter:

Few programmers stuff so much on one line that it becomes difficult picking out
the error.<

If you write D code in functional-style then lines of code often become quite long. Bye, bearophile
Aug 29 2011
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/27/11 12:14 PM, Benjamin Thaut wrote:
 After having used the D 2.0 programming language for a year now and
 having completed 3 projects with it, I wrote a small article about the
 problems I had with the D 2.0 programming language and what suggestions
 I have to improve it.

 http://3d.benjamin-thaut.de/?p=18

On reddit: http://www.reddit.com/r/programming/comments/jwkvx/suggestions_for_the_d_20_programming_language/ Andrei
Aug 27 2011
next sibling parent reply kennytm <kennytm gmail.com> writes:
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 On 8/27/11 12:14 PM, Benjamin Thaut wrote:
 After having used the D 2.0 programming language for a year now and
 having completed 3 projects with it, I wrote a small article about the
 problems I had with the D 2.0 programming language and what suggestions
 I have to improve it.
 
 http://3d.benjamin-thaut.de/?p=18

On reddit: http://www.reddit.com/r/programming/comments/jwkvx/suggestions_for_the_d_20_programming_language/ Andrei

On the pattern matching syntax for templates in the comments -- Sigh, the spec gotta advertise this valid syntax in the operator overloading page more: Foo opBinary(string op:"+")(...) { ... }
Aug 28 2011
parent reply =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= <xtzgzorex gmail.com> writes:
On 29-08-2011 18:15, Andrej Mitrovic wrote:
 On 8/29/11, kennytm<kennytm gmail.com>  wrote:
 On the pattern matching syntax for templates in the comments -- Sigh, the
 spec gotta advertise this valid syntax in the operator overloading page
 more:

      Foo opBinary(string op:"+")(...) { ... }

Wow I didn't know about this. So now I can do this: enum Foo { A, B } void test(Foo foo:Foo.A)() {} instead of the more verbose: void test(Foo foo)() if (foo == Foo.A) {}

Can it be used for overloading? I assume the way it works in that code is that it only runs the function if foo equals Foo.A. - Alex
Aug 29 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/29/2011 06:30 PM, Alex Rnne Petersen wrote:
 On 29-08-2011 18:15, Andrej Mitrovic wrote:
 On 8/29/11, kennytm<kennytm gmail.com> wrote:
 On the pattern matching syntax for templates in the comments -- Sigh,
 the
 spec gotta advertise this valid syntax in the operator overloading page
 more:

 Foo opBinary(string op:"+")(...) { ... }

Wow I didn't know about this. So now I can do this: enum Foo { A, B } void test(Foo foo:Foo.A)() {} instead of the more verbose: void test(Foo foo)() if (foo == Foo.A) {}

Can it be used for overloading? I assume the way it works in that code is that it only runs the function if foo equals Foo.A. - Alex

Yes: void test(Foo foo)() {} // handles Foo.A void test(Foo foo:Foo.B)() {} // handles Foo.B
Aug 29 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 08/29/2011 07:44 PM, Martin Nowak wrote:
 On Mon, 29 Aug 2011 18:55:56 +0200, Andrej Mitrovic
 <andrej.mitrovich gmail.com> wrote:

 Oh man wouldn't it be cool if we could use this syntax like this:

 void test(R1:isInputRange, R2:isForwardRange)(R1 r1, R2 r2) {}

 I'm not sure how that would work with multiple constraints or
 constraints that need comparisons, e.g. ElementType:

 void test(R1:isInputRange && ElementType == int, R2:isForwardRange)() {}

 Just throwing ideas for D5 there.. lol.

Well, can you come up with a useful syntax for void put(E, R)(R r, E e) if(is(E : ElementType!R)) {} et.al. Otherwise having another syntax which put the sometimes heavy template constraints on the exact opposite side of the function signature is not too tempting.

void put(E: ElementType!R, R)(R r, E e) {}
Aug 29 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/29/11 1:39 PM, Timon Gehr wrote:
 On 08/29/2011 07:44 PM, Martin Nowak wrote:
 On Mon, 29 Aug 2011 18:55:56 +0200, Andrej Mitrovic
 <andrej.mitrovich gmail.com> wrote:

 Oh man wouldn't it be cool if we could use this syntax like this:

 void test(R1:isInputRange, R2:isForwardRange)(R1 r1, R2 r2) {}

 I'm not sure how that would work with multiple constraints or
 constraints that need comparisons, e.g. ElementType:

 void test(R1:isInputRange && ElementType == int, R2:isForwardRange)() {}

 Just throwing ideas for D5 there.. lol.

Well, can you come up with a useful syntax for void put(E, R)(R r, E e) if(is(E : ElementType!R)) {} et.al. Otherwise having another syntax which put the sometimes heavy template constraints on the exact opposite side of the function signature is not too tempting.

void put(E: ElementType!R, R)(R r, E e) {}

The if-restriction on a template may build arbitrary expressions, so this case is addressed by pattern matching through "luck". So we definitely need if-restricted templates. Though I agree pattern matching syntax is nice, it is but an inferior alternative. Andrei
Aug 29 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/29/2011 08:59 PM, Andrei Alexandrescu wrote:
 On 8/29/11 1:39 PM, Timon Gehr wrote:
 On 08/29/2011 07:44 PM, Martin Nowak wrote:
 On Mon, 29 Aug 2011 18:55:56 +0200, Andrej Mitrovic
 <andrej.mitrovich gmail.com> wrote:

 Oh man wouldn't it be cool if we could use this syntax like this:

 void test(R1:isInputRange, R2:isForwardRange)(R1 r1, R2 r2) {}

 I'm not sure how that would work with multiple constraints or
 constraints that need comparisons, e.g. ElementType:

 void test(R1:isInputRange && ElementType == int,
 R2:isForwardRange)() {}

 Just throwing ideas for D5 there.. lol.

Well, can you come up with a useful syntax for void put(E, R)(R r, E e) if(is(E : ElementType!R)) {} et.al. Otherwise having another syntax which put the sometimes heavy template constraints on the exact opposite side of the function signature is not too tempting.

void put(E: ElementType!R, R)(R r, E e) {}

The if-restriction on a template may build arbitrary expressions, so this case is addressed by pattern matching through "luck". So we definitely need if-restricted templates. Though I agree pattern matching syntax is nice, it is but an inferior alternative.

I am not sure that we are talking about the same thing. This does not actually compile now, because the compiler does never instantiate the template when performing pattern matching, so pattern matching only works with template structs/classes. Andrej's suggestion was to actually allow arbitrary expressions: Andrej Mitrovic wrote:
 void test(R1:isInputRange && ElementType == int,
 R2:isForwardRange)() {}

Basically, in an ideal world, it could be written more like this: void test(R1: InputRange!int, R2: ForwardRange!_)() {} But I don't consider that important. For me, guards are good enough to specify static duck typing interfaces.
Aug 29 2011
prev sibling next sibling parent "Marco Leise" <Marco.Leise gmx.de> writes:
Am 29.08.2011, 05:44 Uhr, schrieb kennytm <kennytm gmail.com>:

 On the pattern matching syntax for templates in the comments -- Sigh, the
 spec gotta advertise this valid syntax in the operator overloading page
 more:

     Foo opBinary(string op:"+")(...) { ... }

Is 'more' an euphemism? ;) Good to know this syntax is possible, thx for clarifying.
Aug 28 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 8/29/11, kennytm <kennytm gmail.com> wrote:
 On the pattern matching syntax for templates in the comments -- Sigh, the
 spec gotta advertise this valid syntax in the operator overloading page
 more:

     Foo opBinary(string op:"+")(...) { ... }

Wow I didn't know about this. So now I can do this: enum Foo { A, B } void test(Foo foo:Foo.A)() {} instead of the more verbose: void test(Foo foo)() if (foo == Foo.A) {}
Aug 29 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Oh man wouldn't it be cool if we could use this syntax like this:

void test(R1:isInputRange, R2:isForwardRange)(R1 r1, R2 r2) {}

I'm not sure how that would work with multiple constraints or
constraints that need comparisons, e.g. ElementType:

void test(R1:isInputRange && ElementType == int, R2:isForwardRange)() {}

Just throwing ideas for D5 there.. lol.
Aug 29 2011
prev sibling next sibling parent "Martin Nowak" <dawg dawgfoto.de> writes:
On Mon, 29 Aug 2011 18:55:56 +0200, Andrej Mitrovic  
<andrej.mitrovich gmail.com> wrote:

 Oh man wouldn't it be cool if we could use this syntax like this:

 void test(R1:isInputRange, R2:isForwardRange)(R1 r1, R2 r2) {}

 I'm not sure how that would work with multiple constraints or
 constraints that need comparisons, e.g. ElementType:

 void test(R1:isInputRange && ElementType == int, R2:isForwardRange)() {}

 Just throwing ideas for D5 there.. lol.

Well, can you come up with a useful syntax for void put(E, R)(R r, E e) if(is(E : ElementType!R)) {} et.al. Otherwise having another syntax which put the sometimes heavy template constraints on the exact opposite side of the function signature is not too tempting.
Aug 29 2011
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Yeah it's not important. But I'll definitely use the colon syntax more
often now.
Aug 29 2011
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/27/2011 10:14 AM, Benjamin Thaut wrote:
 Comments and criticism welcome

This guy wants to contact you: http://www.reddit.com/r/programming/comments/jwkvx/suggestions_for_the_d_20_programming_language/c2g2wos
Aug 29 2011
parent Benjamin Thaut <code benjamin-thaut.de> writes:
Am 29.08.2011 23:12, schrieb Walter Bright:
 On 8/27/2011 10:14 AM, Benjamin Thaut wrote:
 Comments and criticism welcome

This guy wants to contact you: http://www.reddit.com/r/programming/comments/jwkvx/suggestions_for_the_d_20_programming_language/c2g2wos

Thanks for the heads up -- Kind Regards Benjamin Thaut
Aug 30 2011
prev sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Sean Kelly (sean invisibleduck.org)'s article
 I really need to fix this.  It's a pain though, for the reasons related
 to the ones you mention in "5. Shared".  A tid, for example, fronts a
 message queue object that has some shared interface elements and some
 unshared interface elements.  The shared portion, rather than labeling
 functions as synchronized, uses synchronized internally to make the
 mutex use as fine-grained as possible.  And the logically unshared
 portion only synchronizes when accessing the shared data in the object.
 So to make Tid work with shared I would basically have to label the
 shared methods as shared and re-evaluate the ASM output once the
 compiler inserts memory barriers, and cast away shared when accessing
 the message queue from within its owner thread.  What gets me about all
 this is that rather than helping me, the type system is working against
 me.  I love shared as far as its use for globals is concerned, and for
 concrete variables, but not so much for classes.

Yea, shared really was a blunder at least in anything like its current form. I think it's time we just admit it and do our best to mitigate it or find a way to massively overhaul it (though I'm skeptical that it can be overhauled successfully, especially with the constraints on backwards compatibility). The default thread-local/explicit global was a great idea, as was providing a share-nothing-except-immutable message passing-based concurrency module in Phobos for people who want safe, simple, coarse-grained concurrency. Message passing is safe and good for a lot of stuff, but not everything. Once you're trying to use a threading paradigm where you need shared mutable state, though, it can't be safe and it's a waste of time for the language to try. Even if you get rid of low-level data races, you still need to worry about high-level invariants, so you've only won half the battle. Furthermore, the shared type constructor cripples shared-state multithreading so much that it's almost useless unless you do some casting, defeating its purpose. The way I see this evolving is that almost all multithreaded code in D will either: 1. Avoid sharing and just use some combination of straight message passing and immutable data. 2. Bypass shared with casts, use of core.thread, std.parallelism, etc. and just do threading the old-fashioned way. (Though shared-state multithreading can be made less dangerous by encapsulating high-level paradigms. In this respect std.parallelism represents a middle ground between the completely safe std.concurrency and the completely flexible core.thread.) Ironically, I don't see this as such a bad outcome, except for the wasted "shared" keyword and dead trees describing it. D is a systems language and there needs to be ways to do dangerous, unchecked multithreading. It's great to provide a safe but limited way to write concurrent programs (such as share-nothing message passing), it's a no-brainer to prohibit the dangerous ways in SafeD, and it's fine to require some explicitness when using the dangerous ways (such as importing a different module). However, fighting the type system every inch of the way while paying lip service to playing nice with shared is not an acceptable solution. If you need shared state then you're almost guaranteed to need to cast away shared all over the place, and if you need to do so then you may as well bypass it entirely because it's just getting in the way and not providing any safety. This is why I've been so adamant about keeping core.thread and std.parallelism the way they are unless shared massively improves in ways that I'm very skeptical are even possible.
Aug 30 2011
next sibling parent dsimcha <dsimcha yahoo.com> writes:
On 8/30/2011 8:01 PM, Sean Kelly wrote:

 I'd like to say that the 'shared' attribute on member functions should just
mean "make this member visible through a shared reference" and do away with the
memory barriers idea entirely, except that D really does need some form of
atomics.  I'm really not sure what the solution is here.

What's wrong with core.atomic?
Aug 30 2011
prev sibling next sibling parent dsimcha <dsimcha yahoo.com> writes:
On 8/30/2011 8:01 PM, Sean Kelly wrote:
 I'd like to say that the 'shared' attribute on member functions should just
mean "make this member visible through a shared reference"

So the idea would just be that shared is a programmer-verified seal of approval that "yes, this is thread-safe without the user of the object taking any additional precautions"?
Aug 30 2011
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2011-08-31 00:01:09 +0000, Sean Kelly <sean invisibleduck.org> said:

 I'd like to say that the 'shared' attribute on member functions should
 just mean "make this member visible through a shared reference" and do
 away with the memory barriers idea entirely, except that D really does
 need some form of atomics.  I'm really not sure what the solution is
 here.

I think D needs some kind of knowledge about memory regions into its type system. The challenge is to not add too much complexity. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Aug 30 2011
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/30/2011 5:01 PM, Sean Kelly wrote:
 I'd like to say that the 'shared' attribute on member functions should just
 mean "make this member visible through a shared reference" and do away with
 the memory barriers idea entirely, except that D really does need some form
 of atomics.  I'm really not sure what the solution is here.

I'm tending to agree that shared should no longer imply memory barriers.
Sep 01 2011
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
On Aug 27, 2011, at 10:14 AM, Benjamin Thaut wrote:

 After having used the D 2.0 programming language for a year now and =

problems I had with the D 2.0 programming language and what suggestions = I have to improve it. "Either the builtin assert should be configureable so that it triggers a = breakpoint before throwing the exception, or there sould be a way to = built a custom assert" You can use core.exception.setAssetHandler to override the default = assert behavior. This is deprecated, however, because to my knowledge = no one has ever used it and because you can't actually return from this = handler--you must throw. This is because DMD doesn't generate a valid = call stack around the assert call for efficiency reasons.=
Aug 30 2011
prev sibling next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
On Aug 27, 2011, at 10:14 AM, Benjamin Thaut wrote:

 After having used the D 2.0 programming language for a year now and =

problems I had with the D 2.0 programming language and what suggestions = I have to improve it. Here's another one: "8. std.concurreny TID does not support shared" I really need to fix this. It's a pain though, for the reasons related = to the ones you mention in "5. Shared". A tid, for example, fronts a = message queue object that has some shared interface elements and some = unshared interface elements. The shared portion, rather than labeling = functions as synchronized, uses synchronized internally to make the = mutex use as fine-grained as possible. And the logically unshared = portion only synchronizes when accessing the shared data in the object. = So to make Tid work with shared I would basically have to label the = shared methods as shared and re-evaluate the ASM output once the = compiler inserts memory barriers, and cast away shared when accessing = the message queue from within its owner thread. What gets me about all = this is that rather than helping me, the type system is working against = me. I love shared as far as its use for globals is concerned, and for = concrete variables, but not so much for classes.=
Aug 30 2011
parent Kagamin <spam here.lot> writes:
Sean Kelly Wrote:

 The shared portion, rather than labeling functions as synchronized, uses
synchronized internally to make the mutex use as fine-grained as possible.  And
the logically unshared portion only synchronizes when accessing the shared data
in the object.

What's the difference? Both access shared data and synchronize. If the data accessed is unshared, there should be no problem to do it from shared method - there will be no barriers because the data is unshared, as I understand it.
Aug 31 2011
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
On Aug 30, 2011, at 1:41 PM, dsimcha wrote:

 =3D=3D Quote from Sean Kelly (sean invisibleduck.org)'s article
 I really need to fix this.  It's a pain though, for the reasons =


 to the ones you mention in "5. Shared".  A tid, for example, fronts a
 message queue object that has some shared interface elements and some
 unshared interface elements.  The shared portion, rather than =


 functions as synchronized, uses synchronized internally to make the
 mutex use as fine-grained as possible.  And the logically unshared
 portion only synchronizes when accessing the shared data in the =


 So to make Tid work with shared I would basically have to label the
 shared methods as shared and re-evaluate the ASM output once the
 compiler inserts memory barriers, and cast away shared when accessing
 the message queue from within its owner thread.  What gets me about =


 this is that rather than helping me, the type system is working =


 me.  I love shared as far as its use for globals is concerned, and =


 concrete variables, but not so much for classes.

Yea, shared really was a blunder at least in anything like its current =

 think it's time we just admit it and do our best to mitigate it or =

 massively overhaul it (though I'm skeptical that it can be overhauled
 successfully, especially with the constraints on backwards =

=20
 The default thread-local/explicit global was a great idea, as was =

 share-nothing-except-immutable message passing-based concurrency =

 for people who want safe, simple, coarse-grained concurrency.  Message =

 safe and good for a lot of stuff, but not everything.
=20
 Once you're trying to use a threading paradigm where you need shared =

 state, though, it can't be safe and it's a waste of time for the =

I think the idea behind shared as it applies to classes is that the = desired application won't have many shared objects, and those that are = shared should typically be fairly simple things like containers of = objects that don't have external references. The typical "web of shared = objects" as per Java is an invitation to disaster, and so the model = rightly discourages that. Regarding classes, I think one fundamental problem is that shared is = transitive. Simply putting memory barriers between accesses to shared = data doesn't mean that the algorithm itself will be correct if executed = concurrently. Transitively applying shared to member data and allowing = lock-free operations on this data and having the compiler even insert = memory barriers suggests to the neophyte user (IMO) that this is a safe = and acceptable means for making a class multithreaded when nothing could = be further from the truth. Another issue with transitivity is how this = affects C API calls, as the recent flurry of Windows patches to Phobos = can attest.
 Even if you get rid of low-level data races, you still need to worry =

 high-level invariants, so you've only won half the battle.  =

 shared type constructor cripples shared-state multithreading so much =

 almost useless unless you do some casting, defeating its purpose.  The =

 this evolving is that almost all multithreaded code in D will either:
=20
 1.  Avoid sharing and just use some combination of straight message =

 immutable data.
=20
 2.  Bypass shared with casts, use of core.thread, std.parallelism, =

 do threading the old-fashioned way. (Though shared-state =

 made less dangerous by encapsulating high-level paradigms.  In this =

 std.parallelism represents a middle ground between the completely safe
 std.concurrency and the completely flexible core.thread.)

Regarding #1, I do think there's a case to be made for having mutable = shared data, but that data can't be terribly complex. I do very much = dislike having to cast away shared though, because it makes for a very = awkward API design. For example, say I want to use synchronized in a = fine-grained manner. I have to do something like this: class MyClass { shared void doSomething() { cast(Unshared!(MyClass)).doSomething_(); } private void doSomething_() { =85 synchronized(this) { =85 } =85 }
 Ironically, I don't see this as such a bad outcome, except for the =

 keyword and dead trees describing it.  D is a systems language and =

 be ways to do dangerous, unchecked multithreading.  It's great to =

 but limited way to write concurrent programs (such as share-nothing =

 passing), it's a no-brainer to prohibit the dangerous ways in SafeD, =

 to require some explicitness when using the dangerous ways (such as =

 different module).  However, fighting the type system every inch of =

 paying lip service to playing nice with shared is not an acceptable =

 you need shared state then you're almost guaranteed to need to cast =

 all over the place, and if you need to do so then you may as well =

 entirely because it's just getting in the way and not providing any =

 is why I've been so adamant about keeping core.thread and =

 they are unless shared massively improves in ways that I'm very =

 possible.

And this is why I haven't made much effort to change core.thread. I've = actually tried twice so far and gave up each time after seeing the = cascade of changes necessary. I'd like to say that the 'shared' attribute on member functions should = just mean "make this member visible through a shared reference" and do = away with the memory barriers idea entirely, except that D really does = need some form of atomics. I'm really not sure what the solution is = here.=
Aug 30 2011
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
I meant atomic types, though I could probably be convinced otherwise.

Sent from my iPhone

On Aug 30, 2011, at 5:25 PM, dsimcha <dsimcha yahoo.com> wrote:

 On 8/30/2011 8:01 PM, Sean Kelly wrote:
=20
 I'd like to say that the 'shared' attribute on member functions should ju=


th the memory barriers idea entirely, except that D really does need some fo= rm of atomics. I'm really not sure what the solution is here.
=20
 What's wrong with core.atomic?

Aug 31 2011
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
The effect on storage for statics is fantastic. I wasn't suggesting changing=
 that, if that's what you meant.=20

Sent from my iPhone

On Aug 30, 2011, at 5:42 PM, Michel Fortin <michel.fortin michelf.com> wrote=
:

 On 2011-08-31 00:01:09 +0000, Sean Kelly <sean invisibleduck.org> said:
=20
 I'd like to say that the 'shared' attribute on member functions should
 just mean "make this member visible through a shared reference" and do
 away with the memory barriers idea entirely, except that D really does
 need some form of atomics.  I'm really not sure what the solution is
 here.

I think D needs some kind of knowledge about memory regions into its type s=

=20
=20
 --=20
 Michel Fortin
 michel.fortin michelf.com
 http://michelf.com/
=20

Aug 31 2011
prev sibling next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
The unshared methods are only ever meant to be called by the queue owner. Th=
ey access some member data without synchronization to make the queue efficie=
nt for receive calls. I could make these methods shared anyway, but if they w=
ere called concurrently by accident it would mean data corruption.=20

Sent from my iPhone

On Aug 31, 2011, at 12:37 AM, Kagamin <spam here.lot> wrote:

 Sean Kelly Wrote:
=20
 The shared portion, rather than labeling functions as synchronized, uses s=


nd the logically unshared portion only synchronizes when accessing the share= d data in the object.
=20
 What's the difference? Both access shared data and synchronize. If the dat=

od - there will be no barriers because the data is unshared, as I understand= it.
Aug 31 2011
parent Kagamin <spam here.lot> writes:
Sean Kelly Wrote:

 The unshared methods are only ever meant to be called by the queue owner. They
access some member data without synchronization to make the queue efficient for
receive calls. I could make these methods shared anyway, but if they were
called concurrently by accident it would mean data corruption.

If member data of a shared object is non-shared, it can be probably separated into another object, which will be really unshared. Unshared object can aggregate shared part through alias this if you want to see them as one object.
Aug 31 2011
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
That would be the easiest thing, yeah. I had some more complex ideas in the c=
oncurrency list, but dunno if they're practical.=20

Sent from my iPhone

On Aug 30, 2011, at 5:37 PM, dsimcha <dsimcha yahoo.com> wrote:

 On 8/30/2011 8:01 PM, Sean Kelly wrote:
 I'd like to say that the 'shared' attribute on member functions should ju=


=20
 So the idea would just be that shared is a programmer-verified seal of app=

ny additional precautions"?
=20

Aug 31 2011
prev sibling parent Sean Kelly <sean invisibleduck.org> writes:
On Aug 31, 2011, at 11:36 AM, Kagamin wrote:

 Sean Kelly Wrote:
=20
 The unshared methods are only ever meant to be called by the queue =


queue efficient for receive calls. I could make these methods shared = anyway, but if they were called concurrently by accident it would mean = data corruption.
=20
 If member data of a shared object is non-shared, it can be probably =

object can aggregate shared part through alias this if you want to see = them as one object. Fair enough.=
Aug 31 2011
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/27/2011 8:59 AM, dsimcha wrote:
 When I add the directive:

 pragma(lib, "foo");

 to a file called "bar.d" and then do:

 dmd -c bar.d

 does the object file bar.o or bar.obj contain a directive that reflects the
 pragma, or does pragma(lib) only work when compiling and linking in one step,
 e.g. dmd bar.d?

On Windows, it embeds a reference to the library in the .obj file. The .o format does not support this, so on those platforms it adds "foo.a" to the link command.
Aug 28 2011