www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why can't we derive struct's?

reply Manu <turkeyman gmail.com> writes:
I've long since become bored of this design decision. Is there good
reason for it?
Why should it be impossible to derive a struct?

It can just be a sugar for an `alias this`, but for a case of simple
inheritance, `alias this` can be tedious to spot and understand when
reading the code.
There's also the special case of an empty base-struct. I
**constantly** have to do this:

struct Derived
{
  static if (Base.tupleof.length == 0)
    ref inout(Base) base() inout { return *cast(inout(Base)*)&this; }
  else
    Base base;
  alias base this;

  // the things...
}

If not that, then the derived class gets an aligned field of nothing
populated by one byte of empty base struct.

It also wastes the single `alias this` slot that we get in a
no-multiple-alias-this world.

As far as I can tell, the decision is arbitrary... can we move past this?
Dec 19 2018
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Thursday, 20 December 2018 at 01:40:02 UTC, Manu wrote:
 I've long since become bored of this design decision. Is there 
 good
 reason for it?
 Why should it be impossible to derive a struct?

 It can just be a sugar for an `alias this`,
Yes but another possible semantic for a struct inheritance list would be the structural conformance, i.e duck types, but this will never happen in D since we use constraints for that. This could even be used as a primitive, simple and clean template system, although restricted to struct/union: dummy struct Base { void required(); } struct Foo : Base { void required(){} } // we don't expect a Base as param, but something that's conform with Base, // i.e something that can be statically verified to have `void required();` void call( dummy Base base){} Which in D translates to much, really much verbose and complex code: struct Base { void required(); } struct Foo { void required(){} } void call(B)(B base) if (__traits(hasMember, B, "required") && isSomeFuncion(...) && is(ReturnType!(...) == void)) {} let's say if you want to be 100% exact because nowadays I tend not to use template constraints anymore excepted when they are needed for the correct dispatching to an overload, they are a loss of time otherwise (i know some will hate this alternative point of view... )
Dec 19 2018
parent Manu <turkeyman gmail.com> writes:
On Wed, Dec 19, 2018 at 6:10 PM Basile B. via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Thursday, 20 December 2018 at 01:40:02 UTC, Manu wrote:
 I've long since become bored of this design decision. Is there
 good
 reason for it?
 Why should it be impossible to derive a struct?

 It can just be a sugar for an `alias this`,
Yes but another possible semantic for a struct inheritance list would be the structural conformance, i.e duck types, but this will never happen in D since we use constraints for that. This could even be used as a primitive, simple and clean template system, although restricted to struct/union: dummy struct Base { void required(); } struct Foo : Base { void required(){} } // we don't expect a Base as param, but something that's conform with Base, // i.e something that can be statically verified to have `void required();` void call( dummy Base base){} Which in D translates to much, really much verbose and complex code: struct Base { void required(); } struct Foo { void required(){} } void call(B)(B base) if (__traits(hasMember, B, "required") && isSomeFuncion(...) && is(ReturnType!(...) == void)) {} let's say if you want to be 100% exact because nowadays I tend not to use template constraints anymore excepted when they are needed for the correct dispatching to an overload, they are a loss of time otherwise (i know some will hate this alternative point of view... )
I think strong traits are a different thing, otherwise you're conflating syntax with class inheritance, and nobody will expect that. I mean, I love strong traits, but make them a proper thing. Your suggestion is just kinda weird and nobody would anticipate that. I see no good reason to collide with normal class inheritance syntax that way. And that said, I don't think your answer is a comment on *why* it's not possible today :) I'd like to know the reason it doesn't just work already.
Dec 19 2018
prev sibling next sibling parent Rubn <where is.this> writes:
On Thursday, 20 December 2018 at 01:40:02 UTC, Manu wrote:
 I've long since become bored of this design decision. Is there 
 good
 reason for it?
 Why should it be impossible to derive a struct?

 It can just be a sugar for an `alias this`, but for a case of 
 simple
 inheritance, `alias this` can be tedious to spot and understand 
 when
 reading the code.
 There's also the special case of an empty base-struct. I
 **constantly** have to do this:

 struct Derived
 {
   static if (Base.tupleof.length == 0)
     ref inout(Base) base() inout { return 
 *cast(inout(Base)*)&this; }
   else
     Base base;
   alias base this;

   // the things...
 }

 If not that, then the derived class gets an aligned field of 
 nothing populated by one byte of empty base struct.

 It also wastes the single `alias this` slot that we get in a 
 no-multiple-alias-this world.

 As far as I can tell, the decision is arbitrary... can we move 
 past this?
I imagine inheritance comes with things like being able to cast a Derived* to Base*. How do you delete a Base* without knowing it is derived from? Same goes for "virtual" (C++) functions. Virtual destructors and all that vtable stuff you'd normally get aren't used in struct. Instead you need to use the class type with the garbage collector or some hacky work around with scoped. But classes organize their data any way they want, so you need to use a struct as a shell. Not really a because it's not possible, but just like we don't a lot of other stuff, it's a design decision that was made. Gotta poke Walter and see if he's in the "feel's like he doesn't owe us or anyone an explanation" kind of mood or not.
Dec 19 2018
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/19/2018 5:40 PM, Manu wrote:
 I've long since become bored of this design decision. Is there good
 reason for it?
`alias this` can alias to a function, that doesn't work very well with the base class syntax (you also use alias this to a function).
 Why should it be impossible to derive a struct?
Because polymorphism makes little sense for a value type.
 static if (Base.tupleof.length == 0)
static if (Base.sizeof == 0)
 then the derived class
class? struct? Dessert topping? Floor wax? https://www.youtube.com/watch?v=wPO8PqHGWFU (too bad youtube pulled the video part, it's just audio)
Dec 19 2018
next sibling parent reply Manu <turkeyman gmail.com> writes:
On Wed, Dec 19, 2018 at 7:45 PM Walter Bright via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 12/19/2018 5:40 PM, Manu wrote:
 I've long since become bored of this design decision. Is there good
 reason for it?
`alias this` can alias to a function, that doesn't work very well with the base class syntax (you also use alias this to a function).
Right, by necessity, because an empty struct member takes padded space in the aggregate. I think C++ gets the empty-base-class mechanic right; it doesn't take space. I'm demonstrating crappy code that appears extremely frequently in lieu. Perhaps you have a better suggestion?
 Why should it be impossible to derive a struct?
Because polymorphism makes little sense for a value type.
It's not really polymorphism without a vtable, just simple extension. `alias this` produces the same result, it's just more wordy, kinda ugly, and boilerplate-ey. It also hogs the `alias this` slot.
  > static if (Base.tupleof.length == 0)

 static if (Base.sizeof == 0)
Empty struct has sizeof == 1 no? It certainly takes that many bytes as a member, and that 1 byte is naturally padded out to the alignment of the following member.
Dec 20 2018
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/20/18 3:15 AM, Manu wrote:
 On Wed, Dec 19, 2018 at 7:45 PM Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 12/19/2018 5:40 PM, Manu wrote:
   > static if (Base.tupleof.length == 0)

 static if (Base.sizeof == 0)
Empty struct has sizeof == 1 no? It certainly takes that many bytes as a member, and that 1 byte is naturally padded out to the alignment of the following member.
Yes, it does take 1 byte. I believe the reasoning was so it could have a unique address and be used in an array. It's the same in C++ as well, according to the Internet (except for the base class optimization allowance). Note that C++ compilers aren't *required* to implement this. The difference between inheritance and manual inheritance (i.e. alias this and a member), is that with true inheritance there is no member that has to have it's own distinct address, so it's allowed to take up 0 space But I would expect your boilerplate could be handled via mixin template pretty easily, then it becomes: struct Derived { mixin DeriveFrom!Base; } That it takes up the one alias this slot is a bummer, but really we should implement multiple-alias-this and that problem would be solved. -Steve
Dec 20 2018
next sibling parent Manu <turkeyman gmail.com> writes:
On Thu, Dec 20, 2018 at 7:00 AM Steven Schveighoffer via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On 12/20/18 3:15 AM, Manu wrote:
 On Wed, Dec 19, 2018 at 7:45 PM Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
 On 12/19/2018 5:40 PM, Manu wrote:
   > static if (Base.tupleof.length == 0)

 static if (Base.sizeof == 0)
Empty struct has sizeof == 1 no? It certainly takes that many bytes as a member, and that 1 byte is naturally padded out to the alignment of the following member.
Yes, it does take 1 byte. I believe the reasoning was so it could have a unique address and be used in an array. It's the same in C++ as well, according to the Internet (except for the base class optimization allowance). Note that C++ compilers aren't *required* to implement this. The difference between inheritance and manual inheritance (i.e. alias this and a member), is that with true inheritance there is no member that has to have it's own distinct address, so it's allowed to take up 0 space But I would expect your boilerplate could be handled via mixin template pretty easily, then it becomes: struct Derived { mixin DeriveFrom!Base; }
Right, but that's still pretty shit, and I still don't know what advantage it has? Now the pattern you have to look for to understand you are dealing with a derived type is even more bespoke; every code base will have a different expression for this, and people might do it differently in different cases. Every single person I've interacted with that's encountered D has been surprised by this. I'm not sure there's a good reason for it. I'm not saying the current method shouldn't exist, or that it's bad design or not useful. I'm just saying that BOTH should exist, and the syntax may just be sugar for simple, common, and expected aggregation. It can even call the member 'super', instead of some random name. `alias this` is great, but it's too manual, too much noise, and not searchable, which isn't great for the simple case which is deployed 99% of the time.
 That it takes up the one alias this slot is a bummer, but really we
 should implement multiple-alias-this and that problem would be solved.
That's been accepted for years now... why is there no movement? Is the features as defined incompatible with the implementation of DMD?
Dec 20 2018
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Dec 20, 2018 at 10:20:54AM -0800, Manu via Digitalmars-d wrote:
 On Thu, Dec 20, 2018 at 7:00 AM Steven Schveighoffer via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
[...]
 That it takes up the one alias this slot is a bummer, but really we
 should implement multiple-alias-this and that problem would be
 solved.
That's been accepted for years now... why is there no movement? Is the features as defined incompatible with the implementation of DMD?
There has been multiple attempts to implement it, but none were persistent enough to see it through to the finish line. Maybe it's time to crowdfund a dedicated, full-time effort to bring this into a reality. T -- Latin's a dead language, as dead as can be; it killed off all the Romans, and now it's killing me! -- Schoolboy
Dec 20 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/20/2018 10:38 AM, H. S. Teoh wrote:
 There has been multiple attempts to implement it, but none were
 persistent enough to see it through to the finish line.
Nobody has figured out the semantics of single alias this, either (when faced with class inheritance). The bugzilla issues for it are ample evidence. MI is a Hansel and Gretel feature, where it appears to be all gingerbread and candy, but the witch inevitably appears to pop you in the oven. Other Hansel and Gretel features: 1. monkey patching 2. macros 3. implicit variable declaration 4. preprocessor
Dec 20 2018
next sibling parent reply Manu <turkeyman gmail.com> writes:
On Thu., 20 Dec. 2018, 7:35 pm Walter Bright via Digitalmars-d <
digitalmars-d puremagic.com wrote:

 On 12/20/2018 10:38 AM, H. S. Teoh wrote:
 There has been multiple attempts to implement it, but none were
 persistent enough to see it through to the finish line.
Nobody has figured out the semantics of single alias this, either (when faced with class inheritance). The bugzilla issues for it are ample evidence. MI is a Hansel and Gretel feature, where it appears to be all gingerbread and candy, but the witch inevitably appears to pop you in the oven. Other Hansel and Gretel features: 1. monkey patching 2. macros 3. implicit variable declaration 4. preprocessor
I don't think I've ever wanted multiple inheritance in D, but I do want implicit conversions very often, and occasionally multiple implicit conversions.

Dec 20 2018
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/20/2018 11:23 PM, Manu wrote:
 I don't think I've ever wanted multiple inheritance in D,
That's what multiple alias this is.
 and occasionally multiple implicit conversions.
Another feature that looks great in the small, but turns into a hopeless morass all too quickly. Even C++ gave up on that, which meant it was pretty bad :-) (Basically, nobody could figure out which overload was being called and why.)
Dec 21 2018
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, December 21, 2018 4:28:21 AM MST Walter Bright via Digitalmars-d 
wrote:
 On 12/20/2018 11:23 PM, Manu wrote:
 and occasionally multiple implicit conversions.
Another feature that looks great in the small, but turns into a hopeless morass all too quickly. Even C++ gave up on that, which meant it was pretty bad :-) (Basically, nobody could figure out which overload was being called and why.)
Honestly, over time, I've come to dislike implicit conversions more and more. They cause enough stray bugs with the built-in types without even getting into the issues with user-defined types (issues with implicit conversions with character type and implicit slicing of static arrays come to mind in particular, though the problem is by no means just with them). But what gets particularly bad is templated code. It's trivial to write code that's supposed to work on any type that implictly converts to a particular type but then fail to actually do the conversion in the code, resulting in subtle bugs. The primary fix for this is to _always_ force the conversion if you're writing templated code that is supposed to work with an implicit conversion, but in general, it just works better that the conversion occur outside of the template. So, taking all of that into account, it becomes easy to start viewing implicit conversions in general as being a terrible idea. That being said, there are definitely times where implicit conversions are nice to have, and not having them can get pretty annoying. Also, casting is a blunt enough instrument that it can become easy to end up having explicit conversions that do the wrong thing (especially if the types involved get changed later without the code involving the case being updated). So, echewing implicit conversions can cause other problems (though on the whole, I do think that explicit conversions have far fewer problems - they just can get annoying sometimes). But over time I've become increasingly worried about having the ability to have multiple alias this-es on a type. There's no question that there are times when it would be really useful, but with all of the problems surrounding even a single alias this, having multiple alias this-es on a type starts looking really risky. As it is, I think that having even a single alias this should be done with caution and relatively rarely. And if we had the ability to have multiple alias this-es on a type, I would think that it should be used extremely rarely. But the very fact that it existed could have some nasty repercussions (especially for generic code). I don't know that that means that we shouldn't have the feature, but it definitley concerns me. - Jonathan M Davis
Dec 27 2018
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/27/18 3:15 PM, Jonathan M Davis wrote:
 On Friday, December 21, 2018 4:28:21 AM MST Walter Bright via Digitalmars-d
 wrote:
 On 12/20/2018 11:23 PM, Manu wrote:
 and occasionally multiple implicit conversions.
Another feature that looks great in the small, but turns into a hopeless morass all too quickly. Even C++ gave up on that, which meant it was pretty bad :-) (Basically, nobody could figure out which overload was being called and why.)
We don't have to copy what C++ did.
 
 Honestly, over time, I've come to dislike implicit conversions more and
 more. They cause enough stray bugs with the built-in types without even
 getting into the issues with user-defined types (issues with implicit
 conversions with character type and implicit slicing of static arrays come
 to mind in particular, though the problem is by no means just with them).
 But what gets particularly bad is templated code. It's trivial to write code
 that's supposed to work on any type that implictly converts to a particular
 type but then fail to actually do the conversion in the code, resulting in
 subtle bugs. The primary fix for this is to _always_ force the conversion if
 you're writing templated code that is supposed to work with an implicit
 conversion, but in general, it just works better that the conversion occur
 outside of the template. So, taking all of that into account, it becomes
 easy to start viewing implicit conversions in general as being a terrible
 idea.
Well, implicit conversions of builtin types is not something a mere user can fix. I'd love to fix those problems, but the one DIP that was trying to fix a minuscule part of that was rejected for reasons that don't bode well for other parts. But in terms of implicit casting that's user defined -- those things are fixable (if they are a problem). Quite honestly, if alias this didn't exist, wrapping a type would be monstrously difficult. But it has to be implemented correctly (it's not right now).
 That being said, there are definitely times where implicit conversions are
 nice to have, and not having them can get pretty annoying. Also, casting is
 a blunt enough instrument that it can become easy to end up having explicit
 conversions that do the wrong thing (especially if the types involved get
 changed later without the code involving the case being updated).
Speaking of that, I believe it's possible to have a casting library that is similar to C++'s casting system. We should create one.
 
 But over time I've become increasingly worried about having the ability to
 have multiple alias this-es on a type. There's no question that there are
 times when it would be really useful, but with all of the problems
 surrounding even a single alias this, having multiple alias this-es on a
 type starts looking really risky. As it is, I think that having even a
 single alias this should be done with caution and relatively rarely. And if
 we had the ability to have multiple alias this-es on a type, I would think
 that it should be used extremely rarely. But the very fact that it existed
 could have some nasty repercussions (especially for generic code). I don't
 know that that means that we shouldn't have the feature, but it definitley
 concerns me.
Having multiple alias this's would not increase any of the existing problems really, it just would add one more wrinkle of ambiguity. But I think that behavior should be easily defined and understood. As for my own experience, I can't see myself using multiple alias this much at all, but it's definitely something that seems like an artificial limitation. -Steve
Dec 27 2018
prev sibling parent reply luckoverthere <luckoverthere gmail.cm> writes:
On Thursday, 27 December 2018 at 20:15:04 UTC, Jonathan M Davis 
wrote:
 As it is, I think that having even a single alias this should 
 be done with caution and relatively rarely. And if we had the 
 ability to have multiple alias this-es on a type, I would think 
 that it should be used extremely rarely. But the very fact that 
 it existed could have some nasty repercussions (especially for 
 generic code). I don't know that that means that we shouldn't 
 have the feature, but it definitley concerns me.

 - Jonathan M Davis
Arguably, in a sense, we already have multiple alias this's. It just has to be done through 1 alias this per struct. struct A { int a; }; struct B { A a_; int b; alias a_ this; } struct C { B b_; int c; alias b_ this; } void main() { import std.stdio; C c; c.b = 10; c.a = 20; B b = c; A a = c; writeln( a, " ", b ); }
Dec 27 2018
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Dec 28, 2018 at 12:25:14AM +0000, luckoverthere via Digitalmars-d wrote:
 On Thursday, 27 December 2018 at 20:15:04 UTC, Jonathan M Davis wrote:
 As it is, I think that having even a single alias this should be
 done with caution and relatively rarely. And if we had the ability
 to have multiple alias this-es on a type, I would think that it
 should be used extremely rarely. But the very fact that it existed
 could have some nasty repercussions (especially for generic code). I
 don't know that that means that we shouldn't have the feature, but
 it definitley concerns me.
[...]
 Arguably, in a sense, we already have multiple alias this's. It just
 has to be done through 1 alias this per struct.
 
 
 struct A {
   int a;
 };
 
 struct B {
     A a_;
     int b;
     alias a_ this;
 }
 
 struct C {
     B b_;
     int c;
     alias b_ this;
 }
[...] That's not multiple alias this, that's just a chain of alias this's. A linear class inheritance hierarchy is not equivalent to multiple inheritance. T -- The right half of the brain controls the left half of the body. This means that only left-handed people are in their right mind. -- Manoj Srivastava
Dec 27 2018
parent reply luckoverthere <luckoverthere gmail.cm> writes:
On Friday, 28 December 2018 at 00:36:15 UTC, H. S. Teoh wrote:
 On Fri, Dec 28, 2018 at 12:25:14AM +0000, luckoverthere via 
 Digitalmars-d wrote:
 On Thursday, 27 December 2018 at 20:15:04 UTC, Jonathan M 
 Davis wrote:
 As it is, I think that having even a single alias this 
 should be done with caution and relatively rarely. And if we 
 had the ability to have multiple alias this-es on a type, I 
 would think that it should be used extremely rarely. But the 
 very fact that it existed could have some nasty 
 repercussions (especially for generic code). I don't know 
 that that means that we shouldn't have the feature, but it 
 definitley concerns me.
[...]
 Arguably, in a sense, we already have multiple alias this's. 
 It just has to be done through 1 alias this per struct.
 
 
 struct A {
   int a;
 };
 
 struct B {
     A a_;
     int b;
     alias a_ this;
 }
 
 struct C {
     B b_;
     int c;
     alias b_ this;
 }
[...] That's not multiple alias this, that's just a chain of alias this's. A linear class inheritance hierarchy is not equivalent to multiple inheritance. T
Indeed, keen observation! struct C { A a_; B b_; int c; alias a_ this; alias b_ this; } Sure you can arrange the structure differently and don't need to have one object contain another. Can have the same type for alias this'd. But in the context of the discussion of the comment I was replying to. It is possible to replicate the same feature of multiple alias this, as you can implicitly convert to multiple types.
Dec 27 2018
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Dec 28, 2018 at 12:50:11AM +0000, luckoverthere via Digitalmars-d wrote:
[...]
 struct C {
     A a_;
     B b_;
     int c;
 
     alias a_ this;
     alias b_ this;
 }
[...] Compiler output: Error: there can be only one alias this Nope, still no multiple alias this. :-D T -- Designer clothes: how to cover less by paying more.
Dec 27 2018
prev sibling parent 12345swordy <alexanderheistermann gmail.com> writes:
On Friday, 21 December 2018 at 07:23:41 UTC, Manu wrote:
 On Thu., 20 Dec. 2018, 7:35 pm Walter Bright via Digitalmars-d 
 < digitalmars-d puremagic.com wrote:

 On 12/20/2018 10:38 AM, H. S. Teoh wrote:
 There has been multiple attempts to implement it, but none 
 were persistent enough to see it through to the finish line.
Nobody has figured out the semantics of single alias this, either (when faced with class inheritance). The bugzilla issues for it are ample evidence. MI is a Hansel and Gretel feature, where it appears to be all gingerbread and candy, but the witch inevitably appears to pop you in the oven. Other Hansel and Gretel features: 1. monkey patching 2. macros 3. implicit variable declaration 4. preprocessor
I don't think I've ever wanted multiple inheritance in D, but I do want implicit conversions very often, and occasionally multiple implicit conversions.
I want implicit conversions here as well.What I don't want is this to be achievable via alias this, as you have no control over how it implicit case. I rather to do it via opCast. Alex
Dec 21 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Friday, 21 December 2018 at 03:33:05 UTC, Walter Bright wrote:
 On 12/20/2018 10:38 AM, H. S. Teoh wrote:
 There has been multiple attempts to implement it, but none were
 persistent enough to see it through to the finish line.
Nobody has figured out the semantics of single alias this, either (when faced with class inheritance). The bugzilla issues for it are ample evidence. MI is a Hansel and Gretel feature, where it appears to be all gingerbread and candy, but the witch inevitably appears to pop you in the oven. Other Hansel and Gretel features: 1. monkey patching 2. macros 3. implicit variable declaration 4. preprocessor
I don't think any lisper has ever complained about Lisp macros - on the contrary, it's considered one of Lisp's killer features. It's a shame they're inextricably linked to the syntax (or lack thereof) and that nobody has yet figured out a good macro system that doesn't depend on S-expressions.
Dec 21 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/21/2018 2:42 AM, Atila Neves wrote:
 I don't think any lisper has ever complained about Lisp macros - on the 
 contrary, it's considered one of Lisp's killer features. It's a shame they're 
 inextricably linked to the syntax (or lack thereof) and that nobody has yet 
 figured out a good macro system that doesn't depend on S-expressions.
Probably because Lisp is unusable without macros, sort of like how C and C++ are unusable without the preprocessor. Lisp is a great language for its ideas, and is a fine language for research purposes. But somehow it just never catches on.
Dec 21 2018
parent reply Atila Neves <atila.neves gmail.com> writes:
On Friday, 21 December 2018 at 11:25:18 UTC, Walter Bright wrote:
 On 12/21/2018 2:42 AM, Atila Neves wrote:
 I don't think any lisper has ever complained about Lisp macros 
 - on the contrary, it's considered one of Lisp's killer 
 features. It's a shame they're inextricably linked to the 
 syntax (or lack thereof) and that nobody has yet figured out a 
 good macro system that doesn't depend on S-expressions.
Probably because Lisp is unusable without macros,
Lisp is perfectly usable without macros, it's just that it would never occur to anyone to do that. D is usable without `foreach`, but why would I program with that handicap? In Lisp, not using macros usually means typing "lambda" more than one would like. `foreach` isn't even the best example in D-land, `mixin` is. I think we can agree that `mixin` is a huge win for D. Lisp macros are like that, but much better.
 sort of like how C and C++ are unusable without the 
 preprocessor.
That's completely different - C/C++ have no way to reuse code other than the preprocessor. One technically could write a whole project without it, but it'd be madness. It's not at all like the Lisp case.
 Lisp is a great language for its ideas, and is a fine language 
 for research purposes. But somehow it just never catches on.
That depends on the definition of "catches on". Every Emacs user has to write Lisp (if they don't they might as well use notepad++); Common Lisp, Scheme and Clojure are all on Tiobe's top 50; Emacs Lisp and Clojure both outrank D in Github popularity (Common Lisp isn't that far behind). I dare say there are orders of magnitude more programmers using Lisp in the browser (via Clojurescript) than there are D programmers doing the same.
Dec 21 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/21/2018 3:54 AM, Atila Neves wrote:
 On Friday, 21 December 2018 at 11:25:18 UTC, Walter Bright wrote:
 Probably because Lisp is unusable without macros,
Lisp is perfectly usable without macros,
Technically true. Doubtful that is pragmatically true once a program exceeds a certain size.
 sort of like how C and C++ are unusable without the preprocessor.
That's completely different - C/C++ have no way to reuse code other than the preprocessor. One technically could write a whole project without it, but it'd be madness. It's not at all like the Lisp case.
In my subjective opinion, it is :-)
 Lisp is a great language for its ideas, and is a fine language for research 
 purposes. But somehow it just never catches on.
That depends on the definition of "catches on". Every Emacs user has to write Lisp (if they don't they might as well use notepad++); Common Lisp, Scheme and Clojure are all on Tiobe's top 50; Emacs Lisp and Clojure both outrank D in Github popularity (Common Lisp isn't that far behind). I dare say there are orders of magnitude more programmers using Lisp in the browser (via Clojurescript) than there are D programmers doing the same.
I've written Elisp extensions in Emacs, too. But they were all just a dozen or two lines. It never inspired me to write a larger program in it. I considered adding scripting to microEmacs, but I was going to use Javascript for that. :-) Lisp is an easy language to implement, document, and sandbox, making it handy for use as an embedded scripting language. Javascript takes months to implement by someone experienced writing compilers, making it not the first thing an IDE developer would try. D isn't any more suitable for in-browser code than C++ is. A native language with raw pointers would not be a good choice for an embeddable scripting language. Javascript has been incredibly successful as an embedded language in web pages.
Dec 21 2018
next sibling parent reply Mike Franklin <slavo5150 yahoo.com> writes:
On Friday, 21 December 2018 at 21:42:35 UTC, Walter Bright wrote:
 D isn't any more suitable for in-browser code than C++ is. A 
 native language with raw pointers would not be a good choice 
 for an embeddable scripting language.

 Javascript has been incredibly successful as an embedded 
 language in web pages.
Now that web assembly has arrived, C++ is a perfectly suitable language for the browser. I'm predicting Javascript will become a legacy language for the web in 5 years. and they probably took me 20% of the time had I needed to write a eye-opening experience, and I'm never going back. There may still be a need for Javascript for a few things, but and other general purpose languages that can compile to web assembly is where it's at for the future of the web. And, I don't see why D can't be a major player there, as I know it already has been demonstrated to be: https://forum.dlang.org/post/zwmszfalyeprtyyhxfeq forum.dlang.org Mike
Dec 21 2018
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Dec 21, 2018 at 10:53:28PM +0000, Mike Franklin via Digitalmars-d wrote:
 On Friday, 21 December 2018 at 21:42:35 UTC, Walter Bright wrote:
 D isn't any more suitable for in-browser code than C++ is. A native
 language with raw pointers would not be a good choice for an
 embeddable scripting language.
 
 Javascript has been incredibly successful as an embedded language in
 web pages.
Now that web assembly has arrived, C++ is a perfectly suitable language for the browser. I'm predicting Javascript will become a legacy language for the web in 5 years.
Although I agree with the sentiment that, in the long term, Javascript is a dead-end, I really doubt that it would become obsolete in 5 years. I'm expecting it will be more like 15-20 years, give or take.

 they probably took me 20% of the time had I needed to write a backend

 experience, and I'm never going back.
That's awesome, and in retrospect, not at all surprising, given the -- shall we call it, idiosyncrasies? -- of Javascript. While modern Javascript has come a long way since the early days of "on click, display an annoying flashing marquee", it has never been able to overcome the fundamental design limitations it inherited from those days. Writing non-trivial code in Javascript is an exercise in masochism, and I've had to *maintain* such code in the past. A nightmarish experience I would not wish on anyone.
 There may still be a need for Javascript for a few things, but not

 general purpose languages that can compile to web assembly is where
 it's at for the future of the web.  And, I don't see why D can't be a
 major player there, as I know it already has been demonstrated to be:
 https://forum.dlang.org/post/zwmszfalyeprtyyhxfeq forum.dlang.org
[...] While I still have qualms about the idea of running arbitrary code in a browser (no matter how encapsulated the sandbox is claimed to be), I *would* quite look forward to the day when I don't have to touch Javascript in order to deploy code on the web. Especially if said deployment can be done in D! T -- Never ascribe to malice that which is adequately explained by incompetence. -- Napoleon Bonaparte
Dec 21 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Friday, 21 December 2018 at 21:42:35 UTC, Walter Bright wrote:
 On 12/21/2018 3:54 AM, Atila Neves wrote:
 On Friday, 21 December 2018 at 11:25:18 UTC, Walter Bright 
 wrote:
 Probably because Lisp is unusable without macros,
Lisp is perfectly usable without macros,
Technically true. Doubtful that is pragmatically true once a program exceeds a certain size.
As true as a C program of the same size. They're just better than not using them. I have difficulty not writing macros when I write Lisp, but then again I have difficulty not writing templates when I write C++ or D.
 D isn't any more suitable for in-browser code than C++ is. A 
 native language with raw pointers would not be a good choice 
 for an embeddable scripting language.
And yet, people have been compiling C++ and running it in the browser for a while.
 Javascript has been incredibly successful as an embedded 
 language in web pages.
It has. But with webassembly its days might be numbered.
Dec 22 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/22/2018 2:47 AM, Atila Neves wrote:
 D isn't any more suitable for in-browser code than C++ is. A native language 
 with raw pointers would not be a good choice for an embeddable scripting 
 language.
And yet, people have been compiling C++ and running it in the browser for a while.
I didn't know that. But one can support "raw" pointers in a sandbox via emulation. But then one loses the benefits of raw pointers. It doesn't change my opinion that C++ is unsuitable for in-browser work. As I recall, there is "managed C++" which was Microsoft getting C++ to work with CLI, but they did it by extensively modifying the language. https://en.wikipedia.org/wiki/C%2B%2B/CLI
Dec 26 2018
parent luckoverthere <luckoverthere gmail.cm> writes:
On Wednesday, 26 December 2018 at 22:33:18 UTC, Walter Bright 
wrote:
 On 12/22/2018 2:47 AM, Atila Neves wrote:
 D isn't any more suitable for in-browser code than C++ is. A 
 native language with raw pointers would not be a good choice 
 for an embeddable scripting language.
And yet, people have been compiling C++ and running it in the browser for a while.
I didn't know that. But one can support "raw" pointers in a sandbox via emulation. But then one loses the benefits of raw pointers. It doesn't change my opinion that C++ is unsuitable for in-browser work. As I recall, there is "managed C++" which was Microsoft getting C++ to work with CLI, but they did it by extensively modifying the language. https://en.wikipedia.org/wiki/C%2B%2B/CLI
C++/CLI is dead, long live C++/CX https://en.wikipedia.org/wiki/C%2B%2B/CX
Dec 26 2018
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/20/2018 6:55 AM, Steven Schveighoffer wrote:
 really we should 
 implement multiple-alias-this and that problem would be solved.
And create a host of other problems. Multiple alias this is multiple inheritance with all of C++'s problems with it, and more, because then you wind up with two (count 'em, 2!) multiple inheritance hierarchies. Madness. Even single alias this has spawned a fair amount of wreckage in bugzilla, because people use it for multiple inheritance which it was never intended for. MI is just a bad idea. It's best to just think of another way to structure the data - even if you get it to work, it'll just confuse the poor schlub who has to maintain the code.
Dec 20 2018
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/20/18 10:08 PM, Walter Bright wrote:
 On 12/20/2018 6:55 AM, Steven Schveighoffer wrote:
 really we should implement multiple-alias-this and that problem would 
 be solved.
And create a host of other problems. Multiple alias this is multiple inheritance with all of C++'s problems with it, and more, because then you wind up with two (count 'em, 2!) multiple inheritance hierarchies. Madness. Even single alias this has spawned a fair amount of wreckage in bugzilla, because people use it for multiple inheritance which it was never intended for.
The issues I've seen in bugzilla are how alias this overrides default expected behavior of classes. In other words, if you have a base class and want to cast it to a derived, and the base class has an alias this, it stupidly tries the alias this, and won't even consider a dynamic cast. It's not madness so much as poor implementation. Saying there are bugs in the alias this implementation is not the same as saying the feature is problematic. All that is needed is a good definition of what takes precedence -- we already have that, it's just not implemented properly.
 MI is just a bad idea. It's best to just think of another way to 
 structure the data - even if you get it to work, it'll just confuse the 
 poor schlub who has to maintain the code.
But MI is not multiple alias-this. alias-this is more like an implicit cast, where as multiple inheritance has to deal with the diamond problem, and other issues (like the expectation of base types living at the same address as the derived one). Would you say that C++ operator conversions has all the same problems as MI? -Steve
Dec 21 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/21/2018 11:08 AM, Steven Schveighoffer wrote:
 The issues I've seen in bugzilla are how alias this overrides default expected 
behavior of classes. In other words, if you have a base class and want to cast it to a derived, and the base class has an alias this, it stupidly tries the alias this, and won't even consider a dynamic cast. It's not madness so much as poor implementation. Saying there are bugs in the alias this implementation is not the same as saying the feature is problematic. All that is needed is a good definition of what takes precedence -- we already have that, it's just not implemented properly.
The ones I reviewed do not have easy answers as to what the correct behavior "ought" to be, and it certainly is not spec'ed in the specification.
 But MI is not multiple alias-this.
It fundamentally is. (Though I agree it doesn't have the virtual base "diamond inheritance" issue.)
Dec 21 2018
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/21/18 4:46 PM, Walter Bright wrote:
 On 12/21/2018 11:08 AM, Steven Schveighoffer wrote:
 The issues I've seen in bugzilla are how alias this overrides default 
 expected 
behavior of classes. In other words, if you have a base class and want to cast it to a derived, and the base class has an alias this, it stupidly tries the alias this, and won't even consider a dynamic cast. It's not madness so much as poor implementation. Saying there are bugs in the alias this implementation is not the same as saying the feature is problematic. All that is needed is a good definition of what takes precedence -- we already have that, it's just not implemented properly.
The ones I reviewed do not have easy answers as to what the correct behavior "ought" to be, and it certainly is not spec'ed in the specification.
Which ones? Fundamentally, alias this brings behavior for types where default behavior doesn't exist. For classes, casting to void * or another object is defined, so alias this should not override. Principal of least surprise. That's the only bug I've seen.
 But MI is not multiple alias-this.
It fundamentally is. (Though I agree it doesn't have the virtual base "diamond inheritance" issue.)
In terms of which alias this is used, we have leeway to define whatever we want. Alias this acts like inheritance, but it's NOT inheritance. We can say there is a specific order of precedence between the alias this'd items (I wouldn't recommend that), or we could say more than one alias this being usable in the same expression is an ambiguity error. I don't think the precedence rules are that complicated: 1. The type's members or base classes 2. The type's alias this'd members. Any ambiguities are a compiler error. 3. UFCS functions that accept the type or base classes. 4. UFCS functions that accept any alias this'd type. Any ambiguities are a compiler error. Unlike MI, there is a specific member you can use to disambiguate, which is way less clunky than MI, where you need a cast, or to name the type itself. My vision: void foo(int x) { writeln("foo int"); } void foo(T t) { writeln("foo T"); } void bar(int x) { writeln("bar int"); } void baz(int x) { writeln("baz int"); } void baz(T t) { writeln("baz T"); } void baz(S s) { writeln("baz S"); } void foobar(int x) { writeln("foobar int"); } void foobar(T t) { writeln("foobar T"); } struct T { void bar() { writeln("bar T"); } } struct S { int x; T t; alias this x; alias this t; void foo() { writeln("S");} } S s; s.foo(); // foo S s.bar(); // bar T; members take precedence over UFCS s.baz(); // baz S; main type takes precedence over alias this'd s.foobar(); // Error, both alias this'd have same precednece for UFCS s.x.foobar(); // foobar int s.t.foobar(); // foobar T Don't have the "both alias this'd have the same member" error, but you get the idea. And your example from earlier: class C : B { B b; alias b this; } Basically, the alias this b is never used, because C will always take precedence. If you think any of this is unintuitive, please let me know. -Steve
Dec 21 2018
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/21/18 5:23 PM, Steven Schveighoffer wrote:
 1. The type's members or base classes
 2. The type's alias this'd members. Any ambiguities are a compiler error.
 3. UFCS functions that accept the type or base classes.
 4. UFCS functions that accept any alias this'd type. Any ambiguities are 
 a compiler error.
A simple way to put this is -- if the code would compile WITHOUT alias this, then that's what happens. -Steve
Dec 21 2018
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 12/21/18 5:23 PM, Steven Schveighoffer wrote:

 And your example from earlier:
 
 class C : B
 {
    B b;
    alias b this;
 }
FYI, this already prints a compiler error, which is exactly the right behavior! Error: alias this is not reachable as C already converts to onlineapp.B -Steve
Dec 21 2018
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Dec 21, 2018 at 01:46:45PM -0800, Walter Bright via Digitalmars-d wrote:
 On 12/21/2018 11:08 AM, Steven Schveighoffer wrote:
[...]
 But MI is not multiple alias-this.
It fundamentally is. (Though I agree it doesn't have the virtual base "diamond inheritance" issue.)
It doesn't have to be. It can be treated as imports: if there's any question about what a symbol should resolve to, emit an ambiguity error. T -- It won't be covered in the book. The source code has to be useful for something, after all. -- Larry Wall
Dec 21 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/21/2018 2:43 PM, H. S. Teoh wrote:
 It can be treated as imports:
See my response to Timon.
Dec 24 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 24 December 2018 at 11:46:46 UTC, Walter Bright wrote:
 On 12/21/2018 2:43 PM, H. S. Teoh wrote:
 It can be treated as imports:
See my response to Timon.
My 2 cents is that D needs to allow custom implicit conversion without using alias this.(You shouldn't have to rely on alias this, to get implicit conversations!)
Dec 24 2018
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Dec 24, 2018 at 04:51:09PM +0000, 12345swordy via Digitalmars-d wrote:
 On Monday, 24 December 2018 at 11:46:46 UTC, Walter Bright wrote:
 On 12/21/2018 2:43 PM, H. S. Teoh wrote:
 It can be treated as imports:
See my response to Timon.
My 2 cents is that D needs to allow custom implicit conversion without using alias this.(You shouldn't have to rely on alias this, to get implicit conversations!)
From what I understand, Walter dislikes implicit conversions because of
the horrible mess in C++ caused by implicit conversions and the associated obfuscated tangle of rules that nobody except language lawyers would even begin to understand. T -- Старый друг лучше новых двух.
Dec 24 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 24 December 2018 at 17:08:33 UTC, H. S. Teoh wrote:
 From what I understand, Walter dislikes implicit conversions 
 because of
 the horrible mess in C++ caused by implicit conversions and the 
 associated obfuscated tangle of rules that nobody except 
 language lawyers would even begin to understand.


 T
I understand his concerns. However it doesn't change the fact that people use alias this as way of implicit casting, and people desire custom implicit conversions! *** We can introduce implicit conversations without introducing the mess that is C++!*** Alex
Dec 24 2018
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Dec 24, 2018 at 05:54:45PM +0000, 12345swordy via Digitalmars-d wrote:
 On Monday, 24 December 2018 at 17:08:33 UTC, H. S. Teoh wrote:
 From what I understand, Walter dislikes implicit conversions because
 of the horrible mess in C++ caused by implicit conversions and the
 associated obfuscated tangle of rules that nobody except language
 lawyers would even begin to understand.
[...]
 I understand his concerns. However it doesn't change the fact that
 people use alias this as way of implicit casting, and people desire
 custom implicit conversions!
 *** We can introduce implicit conversations without introducing the
 mess that is C++!***
[...] If you can convince him, that would be great! T -- Designer clothes: how to cover less by paying more.
Dec 24 2018
next sibling parent 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 24 December 2018 at 18:10:16 UTC, H. S. Teoh wrote:
 On Mon, Dec 24, 2018 at 05:54:45PM +0000, 12345swordy via 
 Digitalmars-d wrote:
 On Monday, 24 December 2018 at 17:08:33 UTC, H. S. Teoh wrote:
 From what I understand, Walter dislikes implicit conversions 
 because of the horrible mess in C++ caused by implicit 
 conversions and the associated obfuscated tangle of rules 
 that nobody except language lawyers would even begin to 
 understand.
[...]
 I understand his concerns. However it doesn't change the fact 
 that
 people use alias this as way of implicit casting, and people 
 desire
 custom implicit conversions!
 *** We can introduce implicit conversations without 
 introducing the
 mess that is C++!***
[...] If you can convince him, that would be great! T
If I were to write a DIP on this, I have to wait to see if R-Values is going to be accepted or not. Alex
Dec 24 2018
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/24/2018 10:10 AM, H. S. Teoh wrote:
 If you can convince him, that would be great!
You'd need very compelling use cases. It's like adding more and more horsepower to a car. At some point, it doesn't make the car better. Or like operator overloading. C++ has much more expansive rules for operator overloading. They lead to clever programs, and some people swear by them, but are they *better* programs? For example, * iostreams * regex DSL https://pdfs.semanticscholar.org/e630/5f84bca36251fd5a4ffa5f00e0effc8aaa7d.pdf ? I don't buy it. I've never seen an elegant use of the more expansive power (even though many insist those two examples are elegant).
Dec 24 2018
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Dec 24, 2018 at 11:57:50AM -0800, Walter Bright via Digitalmars-d wrote:
[...]
 Or like operator overloading. C++ has much more expansive rules for
 operator overloading. They lead to clever programs, and some people
 swear by them, but are they *better* programs? For example,
 
 * iostreams
 
 * regex DSL https://pdfs.semanticscholar.org/e630/5f84bca36251fd5a4ffa5f00e0effc8aaa7d.pdf
 
 ? I don't buy it. I've never seen an elegant use of the more expansive
 power (even though many insist those two examples are elegant).
Haha, I happen to have the same opinion on the above two examples as you do. Iostream's (ab)use of << and >> contrary to their intended meaning is absolutely atrocious. The wrong precedence of << and >> (as far as I/O is concerned) leads to required parentheses where you don't expect them, with odd results if you forget. And a readability nightmare when you need to output an integer shifted by some amount (which << is output and which is bit shift?). Not to mention the whole hack on top of a patch on top of a festering bandage concept of I/O manipulators and other such "clever" ideas that focus on solving the wrong problem. The whole thing is a code smell, IMNSHO. Back when I still wrote C++, I avoided iostream like the plague and stuck with cstdio where possible. I've had to debug iostreams-based code before, and it made me cringe every time. And the regex DSL is just ... wow. It takes operator overloading abuse to whole new levels never before imagined. The "regexes" you write with this mess of a design resemble *nothing* like regexes, and had absolutely strange precedence rules due to the abuse of operators to mean things far removed from their usual meanings. And have you seen the error messages? Whoa. It's the epitome of everything that's wrong with C++. This kind of code is barely writable and basically unmaintainable. Two symptoms that point to fundamental problems in the whole design. D's std.regex.ctRegex, for all of its warts, lets you write things like: auto re = ctRegex!`(\w+) ((\w+)(\.(\w+))*)`; while offering the same (arguably better) benefits. Try to write the equivalent with that horrible C++ regex library, and it becomes crystal clear that the D version got it right, warts aside.[1] [1] (Like seriously, just last week I rewrote one of my programs to completely avoid std.regex, because the mere act of using a regex adds 5 *seconds* to the total compilation time. And it's not even a complicated regex to begin with. Though, to be fair, the fact that we're annoyed over seconds rather than minutes or, God forbid, hours, that would have been usual fare in complex C++ projects, is a testament to how far ahead D is in this respect, in spite of said warts.) I've also worked with C++ libraries that overload the comma operator... Oh yes, the evil comma operator plus absolutely evil abuse of operator overloading. Oy. This kind of every-man-for-himself operator overloading leads to unmaintainable code where any piece of syntax can mean absolutely *anything*, because you can overload anything and everything, and you cannot even remotely begin to guess what a piece of code actually does just by looking at it. You might have had a fighting chance if you could only trace the calls to their call targets, but thanks to the lovely C++ blend of overload resolution rules, Koenig lookup, SFINAE, and implicit conversions, you need to be a language lawyer just to figure that out. D got it right by restricting the overloading of <, >, ==, etc., to a couple of consistent functions, instead of C++'s encouraging abuse by allowing arbitrary, unrelated implementations of < and >, for example, while discouraging correct use by requiring excessive boilerplate to overload <, then >, then ==, then !=, then <= and >=, just to be sure you covered all the bases. But I suppose we should count our blessings, that the iostream authors didn't choose to overload < and > for I/O instead of << and >> (which you absolutely could, if you're bent on writing bad code), so there remains something to be appreciated here, I guess.</sarcasm> T -- Skill without imagination is craftsmanship and gives us many useful objects such as wickerwork picnic baskets. Imagination without skill gives us modern art. -- Tom Stoppard
Dec 24 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/24/2018 1:31 PM, H. S. Teoh wrote:

There are technical problems with iostreams as well, such as formatting
options, 
and not being multi-threadable.


 And the regex DSL is just ... wow. It takes operator overloading abuse
 to whole new levels never before imagined.
I've talked to David Abrahams about it. It is a nice piece of engineering, and he's very proud of it. But I was right in my assessment of the abuse of operator overloading, as this sort of thing has just never caught on in the C++ community. Another in the "too much power" category is you can throw any type in C++. Such as an `int`. I've never, ever seen any credible use of that. I'm not in the least surprised that the C++ standard library has an Exception class you're supposed to derive from and throw that.
 This kind of every-man-for-himself operator overloading leads to
 unmaintainable code where any piece of syntax can mean absolutely
 *anything*, because you can overload anything and everything, and you
 cannot even remotely begin to guess what a piece of code actually does
 just by looking at it.  You might have had a fighting chance if you
 could only trace the calls to their call targets, but thanks to the
 lovely C++ blend of overload resolution rules, Koenig lookup, SFINAE,
 and implicit conversions, you need to be a language lawyer just to
 figure that out.
Yeah, that about sums up my argument to David about it.
 But I suppose we should count our blessings, that the iostream authors
 didn't choose to overload < and > for I/O instead of << and >> (which
 you absolutely could, if you're bent on writing bad code), so there
 remains something to be appreciated here, I guess.</sarcasm>
I hated iostreams since the 1980s, but it took about 15 years for the C++ community to gradually come around to the idea that it was a mistake. A feature shouldn't be merely "cool" or "great", especially considering all the features D already has. It needs to enable significantly better code to be written. Better as in more efficient, more understandable, safer, less brittle, less tendency for errors, etc. Note that I didn't say "less typing" (!).
Dec 24 2018
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Dec 24, 2018 at 02:30:57PM -0800, Walter Bright via Digitalmars-d wrote:
 On 12/24/2018 1:31 PM, H. S. Teoh wrote:
[...]
 And the regex DSL is just ... wow. It takes operator overloading
 abuse to whole new levels never before imagined.
I've talked to David Abrahams about it. It is a nice piece of engineering, and he's very proud of it. But I was right in my assessment of the abuse of operator overloading, as this sort of thing has just never caught on in the C++ community.
Ah well, just because something is a nice piece of engineering, doesn't necessarily mean it was a good idea in the first place!
 Another in the "too much power" category is you can throw any type in
 C++.  Such as an `int`. I've never, ever seen any credible use of
 that. I'm not in the least surprised that the C++ standard library has
 an Exception class you're supposed to derive from and throw that.
I used to have a code library that standardized on throwing char* to string literals. It was a lazy man's way of having error messages that masqueraded as error codes / exceptions. Not my proudest moment of software design. :-D Though I'll say that the primary motivation for that was my C background, where everything is an int error code, and my being utterly fed up with code that just returned a non-descript -1 on every kind of failure, or worse, returning the return value of another function that returns an *incompatible* range of int error codes, in a totally inconsistent way (e.g., sometimes the function would return -1, or ERR_XYZ where ERR_* is a series of error codes defined in module A, and sometimes returning errno, which is incompatible with module A's error codes, all jammed into a single int return that the caller could not possibly hope to unambiguously decipher). Worst of all, when a problem occurred I'd get a message like "error -123" with zero hint as to what -123 even means. Having char* as an error code instead ensured (1) there's always a human-readable message you can get out of it, even if you couldn't otherwise interpret it; (2) since char* is unique in the space of string literals, you can freely mix error code returns and not have to worry about ambiguities (the dynamic linker will even "remap error codes" for you so errors from multiple libraries will never be confused for one another); (3) no memory allocation is needed -- at least if you stick to my scheme of returning only string literals. Of course, there are other issues with such a design, but it seemed like a good idea at the time. [...]
 But I suppose we should count our blessings, that the iostream
 authors didn't choose to overload < and > for I/O instead of << and
 (which you absolutely could, if you're bent on writing bad code),
 so there remains something to be appreciated here, I
 guess.</sarcasm>
I hated iostreams since the 1980s, but it took about 15 years for the C++ community to gradually come around to the idea that it was a mistake.
I haven't been keeping up with C++ in any serious way ever since I found D; what's the replacement for iostreams these days? Or is it yet another one of those Irreversible Historical Accidents that's here to stay, in spite of acknowledged flaws, to be patched over by Yet More Language Complications that will make the language require a PhD specializing in C++ just so you can write correct code, since the "obvious" way to write C++ is wrong in more ways than you even knew existed?
 A feature shouldn't be merely "cool" or "great", especially
 considering all the features D already has. It needs to enable
 significantly better code to be written. Better as in more efficient,
 more understandable, safer, less brittle, less tendency for errors,
 etc. Note that I didn't say "less typing" (!).
Unfortunately, all of those points conflict with each other at some level, and it's not immediately obvious which blend of them represents the best balance. T -- VI = Visual Irritation
Dec 24 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/24/2018 3:24 PM, H. S. Teoh wrote:
 I haven't been keeping up with C++ in any serious way ever since I found
 D; what's the replacement for iostreams these days?
Not that I'm aware of. Of course, like C's gets(), it'll never go away.
Dec 24 2018
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Dec 24, 2018 at 03:28:08PM -0800, Walter Bright via Digitalmars-d wrote:
 On 12/24/2018 3:24 PM, H. S. Teoh wrote:
 I haven't been keeping up with C++ in any serious way ever since I
 found D; what's the replacement for iostreams these days?
Not that I'm aware of. Of course, like C's gets(), it'll never go away.
So you're saying that basically my unpopular/unconventional choice of sticking with cstdio all these years was actually the right one?! Scary. T -- Answer: Because it breaks the logical sequence of discussion. / Question: Why is top posting bad?
Dec 24 2018
prev sibling parent bpr <brogoff gmail.com> writes:
On Monday, 24 December 2018 at 23:28:08 UTC, Walter Bright wrote:
 On 12/24/2018 3:24 PM, H. S. Teoh wrote:
 I haven't been keeping up with C++ in any serious way ever 
 since I found
 D; what's the replacement for iostreams these days?
https://github.com/fmtlib/fmt ?
 Not that I'm aware of. Of course, like C's gets(), it'll never 
 go away.
Likely true. Nothing ever goes away.
Dec 25 2018
prev sibling next sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 24 December 2018 at 19:57:50 UTC, Walter Bright wrote:
 On 12/24/2018 10:10 AM, H. S. Teoh wrote:
 If you can convince him, that would be great!
You'd need very compelling use cases. It's like adding more and more horsepower to a car. At some point, it doesn't make the car better. Or like operator overloading. C++ has much more expansive rules for operator overloading. They lead to clever programs, and some people swear by them, but are they *better* programs? For example, * iostreams * regex DSL https://pdfs.semanticscholar.org/e630/5f84bca36251fd5a4ffa5f00e0effc8aaa7d.pdf ? I don't buy it. I've never seen an elegant use of the more expansive power (even though many insist those two examples are elegant).
A use case that pops in my head is to avoiding using inheritance as that is not always ideal tool, when it comes to structs/class as you have no control on how it does implicit conversions. No Basic Event programming. No Design by Introspection. No Data Conversion in Regards to Passing Member Variables. You class/struct may end up with functions/variables that you don't want, which creates needless bloat. If you want to support multiple implicit conversion with the current features, then you need multiple alias this, which is not a good solution as A.) It is multiple inheritance. Which we both agree it is a terrible idea. B.) Multi alias this still hasn't been implemented already. *Throws table*
Dec 24 2018
parent reply Rubn <where is.this> writes:
On Monday, 24 December 2018 at 23:06:26 UTC, 12345swordy wrote:
 On Monday, 24 December 2018 at 19:57:50 UTC, Walter Bright 
 wrote:
 On 12/24/2018 10:10 AM, H. S. Teoh wrote:
 If you can convince him, that would be great!
You'd need very compelling use cases. It's like adding more and more horsepower to a car. At some point, it doesn't make the car better. Or like operator overloading. C++ has much more expansive rules for operator overloading. They lead to clever programs, and some people swear by them, but are they *better* programs? For example, * iostreams * regex DSL https://pdfs.semanticscholar.org/e630/5f84bca36251fd5a4ffa5f00e0effc8aaa7d.pdf ? I don't buy it. I've never seen an elegant use of the more expansive power (even though many insist those two examples are elegant).
A use case that pops in my head is to avoiding using inheritance as that is not always ideal tool, when it comes to structs/class as you have no control on how it does implicit conversions.
When talking implicit conversion (at least in the same sense as C++) you create a new object when doing an implicit conversion. How do you envision the implicit conversion would work?
 No Basic Event programming.
Why do you need implicit conversion for this ?
 No Design by Introspection.
 No Data Conversion in Regards to Passing Member Variables.
 You class/struct may end up with functions/variables that you 
 don't want, which creates needless bloat.
You could just use explicit conversion for this, if that's the case. Other than not having write 1 extra identifier there wouldn't be that much more benefit.
 If you want to support multiple implicit conversion with the 
 current features, then you need multiple alias this, which is 
 not a good solution as
 A.) It is multiple inheritance. Which we both agree it is a 
 terrible idea.
 B.) Multi alias this still hasn't been implemented already. 
 *Throws table*
Idk, all this seems shakey. I avoid implicit conversion as much as possible in C++, the times I do use it usually is because of some other limitation in C++ that can be solved a different way in D. Some concrete examples would help though.
Dec 24 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 24 December 2018 at 23:54:19 UTC, Rubn wrote:

 When talking implicit conversion (at least in the same sense as 
 C++) you create a new object when doing an implicit conversion. 
 How do you envision the implicit conversion would work?
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/implicit
 Why do you need implicit conversion for this ?
I meant that you can't program an event that runs every time an implicit conversion occurs.(Unless you hacked the compiler that does that for you...)
 You could just use explicit conversion for this
I am specifically talking about implicit conversions via inheritance and why it not an idea tool, as (Which I had said before) you have no control on how it does implicit conversions. I am not talking about explicit conversions here.
 If you want to support multiple implicit conversion with the 
 current features, then you need multiple alias this, which is 
 not a good solution as
 A.) It is multiple inheritance. Which we both agree it is a 
 terrible idea.
 B.) Multi alias this still hasn't been implemented already. 
 *Throws table*
Idk, all this seems shakey. I avoid implicit conversion as much as possible in C++, the times I do use it usually is because of some other limitation in C++ that can be solved a different way in D.
... What limitations in C++ are you talking about? Alex
Dec 24 2018
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 25 December 2018 at 04:48:22 UTC, 12345swordy wrote:
 On Monday, 24 December 2018 at 23:54:19 UTC, Rubn wrote:

 [snip]
I am specifically talking about implicit conversions via inheritance and why it not an idea tool, as (Which I had said before) you have no control on how it does implicit conversions. I am not talking about explicit conversions here.
Instead of implicit conversions, what about using something like __traits(compiles, cast(U) T.init) to check whether T can be explicitly casted to U? Then you could just create a canCast function that can detect whether it works or not. You'd still have to write a template function to check, but it works with anything. See https://run.dlang.io/is/CfpvUE
Dec 25 2018
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Tuesday, 25 December 2018 at 15:03:14 UTC, jmh530 wrote:

 to check whether T can be explicitly casted to U?
That is a completely different issue and has nothing to do with implicit conversion. -Alex
Dec 25 2018
prev sibling next sibling parent 12345swordy <alexanderheistermann gmail.com> writes:
On Monday, 24 December 2018 at 19:57:50 UTC, Walter Bright wrote:
 On 12/24/2018 10:10 AM, H. S. Teoh wrote:
 If you can convince him, that would be great!
You'd need very compelling use cases. It's like adding more and more horsepower to a car. At some point, it doesn't make the car better. Or like operator overloading. C++ has much more expansive rules for operator overloading. They lead to clever programs, and some people swear by them, but are they *better* programs? For example, * iostreams * regex DSL https://pdfs.semanticscholar.org/e630/5f84bca36251fd5a4ffa5f00e0effc8aaa7d.pdf ? I don't buy it. I've never seen an elegant use of the more expansive power (even though many insist those two examples are elegant).
Oh btw Merry Christmas! Alex
Dec 24 2018
prev sibling parent reply Rubn <where is.this> writes:
On Monday, 24 December 2018 at 19:57:50 UTC, Walter Bright wrote:
 On 12/24/2018 10:10 AM, H. S. Teoh wrote:
 If you can convince him, that would be great!
You'd need very compelling use cases. It's like adding more and more horsepower to a car. At some point, it doesn't make the car better. Or like operator overloading. C++ has much more expansive rules for operator overloading. They lead to clever programs, and some people swear by them, but are they *better* programs? For example, * iostreams * regex DSL https://pdfs.semanticscholar.org/e630/5f84bca36251fd5a4ffa5f00e0effc8aaa7d.pdf ? I don't buy it. I've never seen an elegant use of the more expansive power (even though many insist those two examples are elegant).
I feel like D's operator overloading can be equally abused as C++'s operator overloading. There just aren't people doing that with D (yet).
Dec 24 2018
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Dec 25, 2018 at 12:15:58AM +0000, Rubn via Digitalmars-d wrote:
 On Monday, 24 December 2018 at 19:57:50 UTC, Walter Bright wrote:
[...]
 Or like operator overloading. C++ has much more expansive rules for
 operator overloading. They lead to clever programs, and some people
 swear by them, but are they *better* programs? For example,
 
 * iostreams
 
 * regex DSL https://pdfs.semanticscholar.org/e630/5f84bca36251fd5a4ffa5f00e0effc8aaa7d.pdf
 
 ? I don't buy it. I've never seen an elegant use of the more
 expansive power (even though many insist those two examples are
 elegant).
I feel like D's operator overloading can be equally abused as C++'s operator overloading. There just aren't people doing that with D (yet).
Many things *can* be abused, but aren't because there's little reason to. D forces you to use opEquals / opCmp for overloading the comparison operators, so at least the behaviour will be (somewhat) consistent no matter how you abuse it. There's also no comma operator for you to abuse. The arithmetic operators can still be abused, but there are also better and easier ways of achieving equivalent results by other means in D, so there's not much incentive to do something like that. For example, compile-time regexes can be achieved by using string mixins, retaining normal regex syntax, so there's not much reason to abuse arithmetic operators with unnatural syntax, just so you can implement compile-time regexes. While << and >> can theoretically still be overloaded iostream-style, D already removed one of the main motivations for ditching C's stdio.h, namely, that the various printf functions are variadic in a non-typesafe way. D actually has 3 different ways of achieving variadic functions, the most common of which is based on variadic templates and completely type-safe. Although some people are not a fan of std.format, it does serve its purpose, and has also been extended in powerful new ways in D (cf., the %(...%) array formatter). There's also the built-in ~ concatenation operator, which can be used for concatenating output strings, and std.conv.text, which formats a list of stuff, so there's less reasons for iostream-style << and >>. Not to mention UFCS, which could be used for chaining output function calls without needing to overload any operators, plus, combined with range-based code, gives you powerful new ways of writing I/O code that essentially marginalizes the utility of iostream-style code. So yeah, it's still *possible* to abuse operator overloading in D, but the incentives for doing that are pretty low, and there are many other nicer features with higher incentives that people are more liable to use instead. It's reminiscient of Walter's Boeing thing, about designing interfaces such that the way people are most likely to use it also happens to be the correct way, whereas the wrong way of doing things requires more effort and/or sticks out like a sore thumb, so people are less likely to attempt it. T -- They pretend to pay us, and we pretend to work. -- Russian saying
Dec 24 2018
parent reply Rubn <where is.this> writes:
On Tuesday, 25 December 2018 at 00:40:13 UTC, H. S. Teoh wrote:
 On Tue, Dec 25, 2018 at 12:15:58AM +0000, Rubn via 
 Digitalmars-d wrote:
 On Monday, 24 December 2018 at 19:57:50 UTC, Walter Bright 
 wrote:
[...]
 Or like operator overloading. C++ has much more expansive 
 rules for operator overloading. They lead to clever 
 programs, and some people swear by them, but are they 
 *better* programs? For example,
 
 * iostreams
 
 * regex DSL 
 https://pdfs.semanticscholar.org/e630/5f84bca36251fd5a4ffa5f00e0effc8aaa7d.pdf
 
 ? I don't buy it. I've never seen an elegant use of the more 
 expansive power (even though many insist those two examples 
 are elegant).
I feel like D's operator overloading can be equally abused as C++'s operator overloading. There just aren't people doing that with D (yet).
Many things *can* be abused, but aren't because there's little reason to. D forces you to use opEquals / opCmp for overloading the comparison operators, so at least the behaviour will be (somewhat) consistent no matter how you abuse it. There's also no comma operator for you to abuse. The arithmetic operators can still be abused, but there are also better and easier ways of achieving equivalent results by other means in D, so there's not much incentive to do something like that. For example, compile-time regexes can be achieved by using string mixins, retaining normal regex syntax, so there's not much reason to abuse arithmetic operators with unnatural syntax, just so you can implement compile-time regexes. While << and >> can theoretically still be overloaded iostream-style, D already removed one of the main motivations for ditching C's stdio.h, namely, that the various printf functions are variadic in a non-typesafe way. D actually has 3 different ways of achieving variadic functions, the most common of which is based on variadic templates and completely type-safe. Although some people are not a fan of std.format, it does serve its purpose, and has also been extended in powerful new ways in D (cf., the %(...%) array formatter). There's also the built-in ~ concatenation operator, which can be used for concatenating output strings, and std.conv.text, which formats a list of stuff, so there's less reasons for iostream-style << and >>. Not to mention UFCS, which could be used for chaining output function calls without needing to overload any operators, plus, combined with range-based code, gives you powerful new ways of writing I/O code that essentially marginalizes the utility of iostream-style code. So yeah, it's still *possible* to abuse operator overloading in D, but the incentives for doing that are pretty low, and there are many other nicer features with higher incentives that people are more liable to use instead. It's reminiscient of Walter's Boeing thing, about designing interfaces such that the way people are most likely to use it also happens to be the correct way, whereas the wrong way of doing things requires more effort and/or sticks out like a sore thumb, so people are less likely to attempt it. T
Being able to and not having a reason to do it are two different things. Someone is going to find a reason to use it and abuse it. Sure you can't overload equality and comma operators, but you can overload just about every other operator. You can easily make the "+" operator do something entirely different than addition. Same with any of the other operators. They can be used with any other type and can output any unrelated type they wish. That's not going to stick out like a sore thumb, and it isn't that much more difficult to do. I wouldn't exactly call this designing an "interface" as it isn't really an interface so much as a feature. I wouldn't say "correct" and "wrong". There's a lot of things in D that are the "correct" way to do something but are incredibly difficult to do and results in messy code. As an example, until very recently you had to write a hack if you wanted to deprecate a single enum value. More accurate words to use would be something a long the lines of "intended design". I mean I could bring up auto-decoding as well, would you say that's the "correct" way or merely the "intended design" falling flat on its' face ending up being incorrect.
Dec 24 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/24/2018 6:43 PM, Rubn wrote:
 You can easily make the "+" operator do something entirely different than 
 addition.
If you want to make "+" non-commutative, you have to work a little harder. I'm happy to see that D has successfully inculcated a culture that attempting to use operator overloading for non-arithmetic purposes is a code smell, rather than celebrating it as C++ does. It's like: #define BEGIN { #define END } is considered a smell in C (it didn't use to be, it took a while to stamp that out). We'll not be accepting such practices into the D standard library, etc., and will do what we can to discourage such. So yes, if you try hard enough, you can write execrable code. But you'll be on your own with it.
Dec 25 2018
parent reply Rubn <where is.this> writes:
On Tuesday, 25 December 2018 at 11:31:17 UTC, Walter Bright wrote:
 On 12/24/2018 6:43 PM, Rubn wrote:
 You can easily make the "+" operator do something entirely 
 different than addition.
If you want to make "+" non-commutative, you have to work a little harder.
Not that hard at all, you just do operator overloading like normal. https://run.dlang.io/is/Jg8Jff struct Int { int value; this( int input ) { value = input; } Int opBinary(string op)(int a) const if ( op == "+" ) { return Int(value + a); } // Hell can make this return a different type and you // won't be even be able to do the comparison: (a + b) == (b + a) Int opBinaryRight(string op)(int a) const if ( op == "+" ) { return Int(value + a + 1); } } void main() { import std.stdio : writeln; const Int a = 5; const int b = 2; writeln(a + b, " == ", b + a); }
 I'm happy to see that D has successfully inculcated a culture 
 that attempting to use operator overloading for non-arithmetic 
 purposes is a code smell, rather than celebrating it as C++ 
 does. It's like:

 #define BEGIN {
 #define END }
 is considered a smell in C (it didn't use to be, it took a 
 while to stamp that out).
What makes you think C++ celebrates it? You just point to one person that thinks it's a good idea. The C++ community has tens of thousands more users than D, there are going to be people that think it is a good idea.
 We'll not be accepting such practices into the D standard 
 library, etc., and will do what we can to discourage such.

 So yes, if you try hard enough, you can write execrable code. 
 But you'll be on your own with it.
Sadly auto-decoding has already made it into the standard. I'm happy to say auto-decoding won't be making its way into the C++ standard :).
Dec 25 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/25/2018 4:50 AM, Rubn wrote:
 What makes you think C++ celebrates it?
The debates about it in the 1980s.
Dec 26 2018
parent Rubn <where is.this> writes:
On Thursday, 27 December 2018 at 01:53:32 UTC, Walter Bright 
wrote:
 On 12/25/2018 4:50 AM, Rubn wrote:
 What makes you think C++ celebrates it?
The debates about it in the 1980s.
So you are basing your opinion on debates from 40 years ago? What debates was D having in the 1980s?
Dec 27 2018
prev sibling parent Neia Neutuladh <neia ikeran.org> writes:
On Tue, 25 Dec 2018 00:15:58 +0000, Rubn wrote:
 I feel like D's operator overloading can be equally abused as C++'s
 operator overloading. There just aren't people doing that with D (yet).
There just aren't as many people thinking that abusing operator overloading is a neat trick these days. I have seen one person using iostream style << in D, which is kind of scary. May as well just use opCall instead if you need one item printed per function call, like Tango did. (And there *are* good reasons for that -- it reduces overhead both at compile time and runtime.)
Dec 24 2018
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/20/2018 12:15 AM, Manu wrote:
 Right, by necessity, because an empty struct member takes padded space
 in the aggregate.
 I think C++ gets the empty-base-class mechanic right; it doesn't take space.
It does take space in C++ depending on the compiler and the circumstance (it's rather complicated). D behaves like the associated C++ compiler in that regard - if it doesn't please file a bug report.
 I'm demonstrating crappy code that appears extremely frequently in lieu.
 Perhaps you have a better suggestion?
 
 Why should it be impossible to derive a struct?
Because polymorphism makes little sense for a value type.
It's not really polymorphism without a vtable, just simple extension. `alias this` produces the same result, it's just more wordy, kinda ugly, and boilerplate-ey.
It seems you have a workaround for what you want to do, and it's a simple paste job. You could probably accomplish the same thing with a mixin template.
 It also hogs the `alias this` slot.
C++ doesn't have alias this, so why would there be a slot for it?
   > static if (Base.tupleof.length == 0)

 static if (Base.sizeof == 0)
Empty struct has sizeof == 1 no? It certainly takes that many bytes as a member,
Not necessarily, see "empty base optimization". But you're right for this particular case. https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Empty_Base_Optimization
Dec 20 2018
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Friday, 21 December 2018 at 03:04:13 UTC, Walter Bright wrote:
 On 12/20/2018 12:15 AM, Manu wrote:
 It also hogs the `alias this` slot.
C++ doesn't have alias this, so why would there be a slot for it?
Its nothing to do with C++. If you do struct "inheritance" with alias this, because there is no multiple alias this, you can't then alias this the struct to something else.
Dec 20 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/20/2018 7:14 PM, Nicholas Wilson wrote:
 If you do struct "inheritance" with alias this, 
 because there is no multiple alias this, you can't then alias this the struct
to 
 something else.
Ok. I suggest using aggregation rather than attempting multiple inheritance.
Dec 20 2018
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Dec 20, 2018 at 12:15:53AM -0800, Manu via Digitalmars-d wrote:
 On Wed, Dec 19, 2018 at 7:45 PM Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
[...]
 Why should it be impossible to derive a struct?
Because polymorphism makes little sense for a value type.
It's not really polymorphism without a vtable, just simple extension. `alias this` produces the same result, it's just more wordy, kinda ugly, and boilerplate-ey. It also hogs the `alias this` slot.
[...] Sigh... when is multiple alias this ever going to happen?? T -- Being forced to write comments actually improves code, because it is easier to fix a crock than to explain it. -- G. Steele
Dec 20 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Thursday, 20 December 2018 at 15:29:50 UTC, H. S. Teoh wrote:
 On Thu, Dec 20, 2018 at 12:15:53AM -0800, Manu via 
 Digitalmars-d wrote:
 On Wed, Dec 19, 2018 at 7:45 PM Walter Bright via 
 Digitalmars-d <digitalmars-d puremagic.com> wrote:
[...]
 Why should it be impossible to derive a struct?
Because polymorphism makes little sense for a value type.
It's not really polymorphism without a vtable, just simple extension. `alias this` produces the same result, it's just more wordy, kinda ugly, and boilerplate-ey. It also hogs the `alias this` slot.
[...] Sigh... when is multiple alias this ever going to happen?? T
When IgorStepanov quit disappearing on us. https://github.com/dlang/dmd/pull/8378 Alex
Dec 20 2018
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Dec 20, 2018 at 03:44:34PM +0000, 12345swordy via Digitalmars-d wrote:
 On Thursday, 20 December 2018 at 15:29:50 UTC, H. S. Teoh wrote:
 On Thu, Dec 20, 2018 at 12:15:53AM -0800, Manu via Digitalmars-d wrote:
 On Wed, Dec 19, 2018 at 7:45 PM Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
[...]
 Why should it be impossible to derive a struct?
Because polymorphism makes little sense for a value type.
It's not really polymorphism without a vtable, just simple extension. `alias this` produces the same result, it's just more wordy, kinda ugly, and boilerplate-ey. It also hogs the `alias this` slot.
[...] Sigh... when is multiple alias this ever going to happen?? T
When IgorStepanov quit disappearing on us. https://github.com/dlang/dmd/pull/8378
[...] IIRC, that PR was blocked because of disagreements over how ambiguous symbols over multiple alias this types would be resolved. Somebody needs to come up with a DIP with well-defined semantics for all the details and corner cases before this can move forward. T -- "Maybe" is a strange word. When mom or dad says it it means "yes", but when my big brothers say it it means "no"! -- PJ jr.
Dec 20 2018
next sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Thursday, 20 December 2018 at 16:10:39 UTC, H. S. Teoh wrote:
 On Thu, Dec 20, 2018 at 03:44:34PM +0000, 12345swordy via 
 Digitalmars-d wrote:
 On Thursday, 20 December 2018 at 15:29:50 UTC, H. S. Teoh 
 wrote:
 On Thu, Dec 20, 2018 at 12:15:53AM -0800, Manu via 
 Digitalmars-d wrote:
 [...]
[...]
 [...]
[...] Sigh... when is multiple alias this ever going to happen?? T
When IgorStepanov quit disappearing on us. https://github.com/dlang/dmd/pull/8378
[...] IIRC, that PR was blocked because of disagreements over how ambiguous symbols over multiple alias this types would be resolved. Somebody needs to come up with a DIP with well-defined semantics for all the details and corner cases before this can move forward. T
Then DIP 66 have failed and needs to be rejected. Alex
Dec 20 2018
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Dec 20, 2018 at 04:45:13PM +0000, 12345swordy via Digitalmars-d wrote:
 On Thursday, 20 December 2018 at 16:10:39 UTC, H. S. Teoh wrote:
 On Thu, Dec 20, 2018 at 03:44:34PM +0000, 12345swordy via Digitalmars-d
 wrote:
 On Thursday, 20 December 2018 at 15:29:50 UTC, H. S. Teoh wrote:
[...]
 Sigh... when is multiple alias this ever going to happen??
[...]
 When IgorStepanov quit disappearing on us.
 https://github.com/dlang/dmd/pull/8378
[...] IIRC, that PR was blocked because of disagreements over how ambiguous symbols over multiple alias this types would be resolved. Somebody needs to come up with a DIP with well-defined semantics for all the details and corner cases before this can move forward.
[...]
 Then DIP 66 have failed and needs to be rejected.
[...] alias this PR. My bad. I see that this is a newer PR submitted just earlier this year. I don't know if it addressed the concerns raised here: https://forum.dlang.org/post/m74pg8$gl4$1 digitalmars.com which I assume would be required to pass scrutiny by W&A. But in any case, there was some feedback but Igor seems to have gone MIA. Hopefully he shows up again soon. I've been waiting for multiple alias this for years now. :-/ T -- Life begins when you can spend your spare time programming instead of watching television. -- Cal Keegan
Dec 20 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Thursday, 20 December 2018 at 18:04:12 UTC, H. S. Teoh wrote:
 On Thu, Dec 20, 2018 at 04:45:13PM +0000, 12345swordy via 
 Digitalmars-d wrote:
 On Thursday, 20 December 2018 at 16:10:39 UTC, H. S. Teoh 
 wrote:
 On Thu, Dec 20, 2018 at 03:44:34PM +0000, 12345swordy via 
 Digitalmars-d wrote:
 On Thursday, 20 December 2018 at 15:29:50 UTC, H. S. Teoh 
 wrote:
[...]
 [...]
[...]
 When IgorStepanov quit disappearing on us. 
 https://github.com/dlang/dmd/pull/8378
[...] IIRC, that PR was blocked because of disagreements over how ambiguous symbols over multiple alias this types would be resolved. Somebody needs to come up with a DIP with well-defined semantics for all the details and corner cases before this can move forward.
[...]
 Then DIP 66 have failed and needs to be rejected.
[...] multiple alias this PR. My bad. I see that this is a newer PR submitted just earlier this year. I don't know if it addressed the concerns raised here: https://forum.dlang.org/post/m74pg8$gl4$1 digitalmars.com which I assume would be required to pass scrutiny by W&A. But in any case, there was some feedback but Igor seems to have gone MIA. Hopefully he shows up again soon. I've been waiting for multiple alias this for years now. :-/ T
Do we have any means of contacting him? That seems like a job of the current PR manager Nicholas Wilson. FFS do we need a crowed funding to finished the damn thing? It been years already, and we can't rely on a single guy who keeps disappearing for long periods of time. -Alex
Dec 20 2018
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Dec 20, 2018 at 06:13:28PM +0000, 12345swordy via Digitalmars-d wrote:
[...]

 multiple alias this PR.  My bad.  I see that this is a newer PR
 submitted just earlier this year. I don't know if it addressed the
 concerns raised here:
 
 	https://forum.dlang.org/post/m74pg8$gl4$1 digitalmars.com
 
 which I assume would be required to pass scrutiny by W&A.  But in
 any case, there was some feedback but Igor seems to have gone MIA.
 Hopefully he shows up again soon.  I've been waiting for multiple
 alias this for years now. :-/
[...]
 Do we have any means of contacting him? That seems like a job of the
 current PR manager Nicholas Wilson. FFS do we need a crowed funding to
 finished the damn thing? It been years already, and we can't rely on a
 single guy who keeps disappearing for long periods of time.
[...] Maybe we should just crowdfund this thing. It's been far too long, and there have been too many failed attempts at it. Maybe past attempts were abandoned because it turned out to be far too much more work than was anticipated, and what it takes is somebody to get paid to dedicate their full time to slogging through all the tedious/complicated bits until it gets to the finish line. T -- Who told you to swim in Crocodile Lake without life insurance??
Dec 20 2018
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 20.12.18 17:10, H. S. Teoh wrote:
 
 IIRC, that PR was blocked because of disagreements over how ambiguous
 symbols over multiple alias this types would be resolved.  Somebody
 needs to come up with a DIP with well-defined semantics for all the
 details and corner cases before this can move forward.
But it's a solved problem. Just make `alias this` exactly like `import`.
Dec 20 2018
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/20/2018 7:21 PM, Timon Gehr wrote:
 But it's a solved problem. Just make `alias this` exactly like `import`.
Imports don't have adjuster thunks, implicit cast issues, slicing, or empty base optimizations. Import lookup in a class is different because of the two-phase nature of it (people complained bitterly about the earlier single phase lookup). Import lookup doesn't have to conform to the relevant undocumented C++ ABI, either. (It was about a year of bug reports until I was finally able to match Microsoft C++'s MFC behavior for MI struct layout.) class C : B { B b; alias b this; } Now what? (This is not specified in the dlang spec.)
Dec 20 2018
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 21/12/2018 5:09 PM, Walter Bright wrote:
 On 12/20/2018 7:21 PM, Timon Gehr wrote:
 But it's a solved problem. Just make `alias this` exactly like `import`.
Imports don't have adjuster thunks, implicit cast issues, slicing, or empty base optimizations. Import lookup in a class is different because of the two-phase nature of it (people complained bitterly about the earlier single phase lookup). Import lookup doesn't have to conform to the relevant undocumented C++ ABI, either. (It was about a year of bug reports until I was finally able to match Microsoft C++'s MFC behavior for MI struct layout.)   class C : B {     B b;     alias b this;   } Now what? (This is not specified in the dlang spec.)
Type Declaration -> alias this [0 .. $] At declaration site or the alias this, if it is not free-of-issues, error. Say didn't we have a DIP that was accepted for multiple alias this?
Dec 20 2018
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 21.12.18 05:09, Walter Bright wrote:
 On 12/20/2018 7:21 PM, Timon Gehr wrote:
 But it's a solved problem. Just make `alias this` exactly like `import`.
Imports don't have adjuster thunks,
Neither does `alias this`.
 implicit cast issues,
Treat implicit casting with `alias this` like an invocation of an imported function.
 slicing,
`alias this` does not have the slicing problem because it can't return something that shares the vtable with the original reference but has a different layout.
 or empty base optimizations.
With `alias this`, empty base optimization has to be done manually.
 Import lookup in a class is different because 
 of the two-phase nature of it (people complained bitterly about the 
 earlier single phase lookup).
 ...
Why should it be different? It's a "look up names in one of those scopes" problem. Same problem, same solution.
 Import lookup doesn't have to conform to the relevant undocumented C++ 
 ABI, either.> (It was about a year of bug reports until I was finally 
 able to match Microsoft C++'s MFC behavior for MI struct layout.)
 ...
Why would multiple `alias this` have to conform to any C++ ABIs?
    class C : B {
      B b;
      alias b this;
    }
 
 Now what? (This is not specified in the dlang spec.)
This is a single alias this problem. But checking imports, this should give ambiguity errors by default (for both member access and implicit/explicit casting) and there should be a way to explicitly disambiguate.
Dec 21 2018
parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/21/2018 5:48 AM, Timon Gehr wrote:
 On 21.12.18 05:09, Walter Bright wrote:
 On 12/20/2018 7:21 PM, Timon Gehr wrote:
 But it's a solved problem. Just make `alias this` exactly like `import`.
Imports don't have adjuster thunks,
Neither does `alias this`.
That depends on how it is specified. For example, should functions found through 'alias this' go into the vtbl[]? (It's not a vacuous question, it has come up with people wanting that to happen. I said no.)
 implicit cast issues,
Treat implicit casting with `alias this` like an invocation of an imported function.
It's not that simple. There are issues with what is considered a "better" match, several of which are in bugzilla w.r.t. alias this.
 slicing,
`alias this` does not have the slicing problem because it can't return something that shares the vtable with the original reference but has a different layout.
That all depends on how one defines how alias this lookup works wrt providing functions to be installed in the vtbl[].
 Import lookup in a class is different because of the two-phase nature of it 
 (people complained bitterly about the earlier single phase lookup).
 ...
Why should it be different? It's a "look up names in one of those scopes" problem. Same problem, same solution.
That isn't how import lookup works today when import declarations appear in classes. It originally worked that way, but nobody understood it. I was UNABLE to explain that import lookup worked exactly like member lookup. I even showed the code which was the same code. But everyone, simply could not understand this and insisted it was behaving bizarrely. So now it is a much more complex 2 phase lookup that behaves "intuitively". It's a great lesson in how "obvious" and "intuitive" behavior for a person is anything but as an algorithm.
 Import lookup doesn't have to conform to the relevant undocumented C++ ABI, 
 either.> (It was about a year of bug reports until I was finally able to match 
 Microsoft C++'s MFC behavior for MI struct layout.)
Why would multiple `alias this` have to conform to any C++ ABIs?
Because people can, will, and do (see Manu) use it to try to emulate struct inheritance for C++ structs.
    class C : B {
      B b;
      alias b this;
    }

 Now what? (This is not specified in the dlang spec.)
This is a single alias this problem. But checking imports, this should give ambiguity errors by default (for both member access and implicit/explicit casting) and there should be a way to explicitly disambiguate.
That isn't how imports work (the base class lookup takes precedence over import lookup). To sum up, the behavior of single alias this is not spec'ed, and there are a lot of decisions to make to tighten that up that are not obvious. All that would have to be done before any multiple alias this can be considered. The experience with MI in C++ was that a seemingly simple idea turned out to have a great deal of unexpected complexity, most of it turning up later. And worse, even when all that was eventually worked out and the implementation bugs fixed, the benefits of MI to programming pretty much failed to materialize.
Dec 21 2018
prev sibling parent Manu <turkeyman gmail.com> writes:
On Thu, Dec 20, 2018 at 8:10 AM H. S. Teoh via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Thu, Dec 20, 2018 at 03:44:34PM +0000, 12345swordy via Digitalmars-d wrote:
 On Thursday, 20 December 2018 at 15:29:50 UTC, H. S. Teoh wrote:
 On Thu, Dec 20, 2018 at 12:15:53AM -0800, Manu via Digitalmars-d wrote:
 On Wed, Dec 19, 2018 at 7:45 PM Walter Bright via Digitalmars-d
 <digitalmars-d puremagic.com> wrote:
[...]
 Why should it be impossible to derive a struct?
Because polymorphism makes little sense for a value type.
It's not really polymorphism without a vtable, just simple extension. `alias this` produces the same result, it's just more wordy, kinda ugly, and boilerplate-ey. It also hogs the `alias this` slot.
[...] Sigh... when is multiple alias this ever going to happen?? T
When IgorStepanov quit disappearing on us. https://github.com/dlang/dmd/pull/8378
[...] IIRC, that PR was blocked because of disagreements over how ambiguous symbols over multiple alias this types would be resolved. Somebody needs to come up with a DIP with well-defined semantics for all the details and corner cases before this can move forward.
Sounds like the original accepted DIP needs to be amended?
Dec 20 2018
prev sibling parent Guillaume Piolat <first.last gmail.com> writes:
On Thursday, 20 December 2018 at 03:42:08 UTC, Walter Bright 
wrote:
 Because polymorphism makes little sense for a value type.
What happens is in D we often want: A - deterministic destruction AND B - reference semantics AND C - sub-typing (interfaces / alias this) `class` does B and C, and even A when emplaced, but not that easy to use. Don't work in -betterC. GC will call destructors which breaks (A) if we aren't careful. `struct` does A, B when wrapped, that not C very well.
Dec 21 2018
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 12/19/2018 5:40 PM, Manu wrote:
 It also wastes the single `alias this` slot that we get in a
 no-multiple-alias-this world.
 
 As far as I can tell, the decision is arbitrary... can we move past this?
T.A. Cargill's famous paper about multiple inheritance: "Controversy: The Case Against Multiple Inheritance in C++" https://www.usenix.org/legacy/publications/compsystems/1991/win_cargill.pdf
Dec 20 2018