www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Types: The Next Generation (Was: Why is phobos so wack?)

reply "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
On 07/09/2017 09:26 AM, Adam D. Ruppe wrote:
 On Sunday, 9 July 2017 at 12:56:55 UTC, FoxyBrown wrote:
 return str.join(" ");
 [...]
 Error: template std.array.join cannot deduce function from argument
 types !()(string, string)
 [...]
 simply trying to join a string[] with a separator.
The error message sucks, but you clearly have a string when you meant string[].
Related to this, I've been giving some thought lately to a little bit of re-designing types themselves. Specifically, type creation tools that go beyond what structs and classes give us and allow better handling D-style generics. It's all very incomplete right now, but basically here's the gist: Awesome as D's generics, ranges, etc all are, they do make two things far more convoluted than when using basic straightforward types: Function declarations, and error messages when things don't match. So, why not encapsulate much of that stuff we merely *describe* in signatures for generic functions into genuine honest-to-goodness types? There would be user-defined symbols, such as "InputRange" or "SomeString", or "RandomAccessRange!SomeString", which the type system sees as actual types. And naturally there would be some mechanism for actually defining those types. Then, defining a function like this: SomeString fizzbar(RandomAccessRange!SomeNumeric r) {...} ...would automatically imply to the compiler all (or at least a lot of) the pluming we usually clutter the function declaration with: Defining the templated types and calling the appropriate if(isBlahBlah) constraints. About the only things remaining would be additional constraints not already defined by the next-gen types, and restrictions on how the parameters relate to each other. Even better, having all that encapsulated into genuine types should make it easier for the compiler to provide better error messages. Thought could also be put into additional type-creation tools that cater specifically to common things (again, such as ranges) to help streamline the process of creating them (ranges are awesome, but let's face it, defining them can be a bother - there's gotta be some way to make it simpler. For example, input ranges especially would GREATLY benefit from And of course, Nemerle-like (ML/Haskell-inspired) algebraics would be a wonderful capability to encorporate as well. Another area to explore would be merging the two sets of parameter lists (the compile-time list and the run-time list) into one list. Certain types would be known to imply "compile-time". A keyword/attr could be used to force compile-time or runtime. And for other params, a sufficiently-smart compiler could conceivably even choose "runtime" vs "compile-time" (or even, "it varies") based on optimization priorities. It would simplify the syntax for users, and help get around fear of templates. Obviously this is all very incomplete, but it's an idea I think is rather interesting.
Jul 09 2017
next sibling parent reply Meta <jared771 gmail.com> writes:
On Sunday, 9 July 2017 at 20:22:16 UTC, Nick Sabalausky 
(Abscissa) wrote:
 On 07/09/2017 09:26 AM, Adam D. Ruppe wrote:
 On Sunday, 9 July 2017 at 12:56:55 UTC, FoxyBrown wrote:
 return str.join(" ");
 [...]
 Error: template std.array.join cannot deduce function from
argument
 types !()(string, string)
 [...]
 simply trying to join a string[] with a separator.
The error message sucks, but you clearly have a string when
you meant
 string[].
Related to this, I've been giving some thought lately to a little bit of re-designing types themselves. Specifically, type creation tools that go beyond what structs and classes give us and allow better handling D-style generics. It's all very incomplete right now, but basically here's the gist: Awesome as D's generics, ranges, etc all are, they do make two things far more convoluted than when using basic straightforward types: Function declarations, and error messages when things don't match. So, why not encapsulate much of that stuff we merely *describe* in signatures for generic functions into genuine honest-to-goodness types? There would be user-defined symbols, such as "InputRange" or "SomeString", or "RandomAccessRange!SomeString", which the type system sees as actual types. And naturally there would be some mechanism for actually defining those types. Then, defining a function like this: SomeString fizzbar(RandomAccessRange!SomeNumeric r) {...} ...would automatically imply to the compiler all (or at least a lot of) the pluming we usually clutter the function declaration with: Defining the templated types and calling the appropriate if(isBlahBlah) constraints. About the only things remaining would be additional constraints not already defined by the next-gen types, and restrictions on how the parameters relate to each other. Even better, having all that encapsulated into genuine types should make it easier for the compiler to provide better error messages.
I'm sorry if I misunderstood what you're proposing, but isn't this exactly what C++ set out to do with concepts? If that's the case, I'd recommend you look up some of Andrei's refutation of concepts in favour of template guards and `static if`.
Jul 09 2017
parent reply Nick Sabalausky <a a.a> writes:
On Sunday, 9 July 2017 at 20:42:39 UTC, Meta wrote:
 I'm sorry if I misunderstood what you're proposing, but isn't 
 this exactly what C++ set out to do with concepts? If that's 
 the case, I'd recommend you look up some of Andrei's refutation 
 of concepts in favour of template guards and `static if`.
Shit, I hope not :/ I gave up following C++ developments 15 years ago. Happen to have a link handy to that refutation?
Jul 09 2017
parent reply Meta <jared771 gmail.com> writes:
On Sunday, 9 July 2017 at 21:59:04 UTC, Nick Sabalausky wrote:
 On Sunday, 9 July 2017 at 20:42:39 UTC, Meta wrote:
 I'm sorry if I misunderstood what you're proposing, but isn't 
 this exactly what C++ set out to do with concepts? If that's 
 the case, I'd recommend you look up some of Andrei's 
 refutation of concepts in favour of template guards and 
 `static if`.
Shit, I hope not :/ I gave up following C++ developments 15 years ago. Happen to have a link handy to that refutation?
There's a couple posts he's made here but a lot of it's spread out across various talks, articles (I think) as well as newsgroup posts. Here's what I found with a quick google: https://www.reddit.com/r/cpp/comments/4jqg5z/andrei_alexandrescu_on_c_concepts/ https://www.reddit.com/r/programming/comments/4jlkhv/accu_2016_keynote_by_andrei_alexandrescu/d391585/ And there's a ton of info on the internet about the C++ concepts proposal.
Jul 09 2017
parent reply Nick Sabalausky <a a.a> writes:
On Sunday, 9 July 2017 at 22:02:51 UTC, Meta wrote:
 There's a couple posts he's made here but a lot of it's spread 
 out across various talks, articles (I think) as well as 
 newsgroup posts. Here's what I found with a quick google:

 https://www.reddit.com/r/cpp/comments/4jqg5z/andrei_alexandrescu_on_c_concepts/
 https://www.reddit.com/r/programming/comments/4jlkhv/accu_2016_keynote_by_andrei_alexandrescu/d391585/

 And there's a ton of info on the internet about the C++ 
 concepts proposal.
Ah, I guess it is very similar after all, except it'd be based on top of and coexist with all of D's design by introspection stuff (rather than exist without it as with C++), thus avoiding a lot of the downsides and getting best of both worlds.
Jul 09 2017
next sibling parent reply "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
  On 07/09/2017 09:21 PM, Nick Sabalausky wrote:
 Ah, I guess it is very similar after all, except it'd be based on top of
 and coexist with all of D's design by introspection stuff (rather than
 exist without it as with C++), thus avoiding a lot of the downsides and
 getting best of both worlds.
Ha ha, I still feel more than a little silly for pitching what amounts to contracts as "an out-there idea I've been mulling over", but indulge in a little (partially-baked) taste to show this at least has some merit anyway. Hell, call it "concepts++" or "concepts, the D way" (note: I'm NOT pitching this as a suggestion for something D should do. Not saying D should or should'nt, just speaking purely in the realm of "langauge design brainstorming" here...Just because it's been on my mind and the "Why is phobos so wack?" thread brought some relevence) Behold! The power of combining constraints/design-by-introspection *with* concepts: Current declaration of std.array.join: --------------------------------------------------- ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror, scope R sep) if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && isInputRange!R && is(Unqual!(ElementType!(ElementType!RoR)) == Unqual!(ElementType!R))); ElementEncodingType!(ElementType!RoR)[] join(RoR, E)(RoR ror, scope E sep) if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && is(E : ElementType!(ElementType!RoR))); ElementEncodingType!(ElementType!RoR)[] join(RoR)(RoR ror) if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR))); --------------------------------------------------- (ie, completely incomprehensible at-a-glance) Just one possibility of an entirely hypothetical D++ (assuming I'm even interpreting the D version correctly): --------------------------------------------------- // Note: This assumes the "ElementEncodingType vs ElementType" distinction // is nothing but a colossal mistake caused purely by the existance of // auto-decoding, which was (as an assumption this psuedo-code is predicated // upon) a complete clusterf*** of misdesign (Ie, *such* a huge stretch of // the imagination ;)), which in this hypothetical ideal langauge has // been killed dead with nuclear fire, and then beaten some more with // spiked crowbars, just to be sure. /++ Params: ror: an input range (or better) of input ranges (or better) of any type (shorthand for 'InputRange!InputRange!Type') sep: a separator that can be any input range ('InputRange!Type'). Returns: Shorthand for 'InputRange!Type': Ie, an input range (or better). Note: This is implicitly templated on typeof(ror) and typeof(sep). +/ InputRange join(InputRange!InputRange ror, InputRange sep) // Relationship constraints: if(UnqualTypeMatch!(ror, sep, return)) /++ Like above, but sep is 'Type' instead of 'InputRange!Type'. Since 'Type' is less specific than 'InputRange!Type', the prior overload is preferred. +/ InputRange join(InputRange!InputRange ror, Type sep) // Relationship constraints: if(unqualTypeMatch!(ror, InputRange!sep, return)) // No separator InputRange join(InputRange!InputRange ror) // Relationship constraints: if(unqualTypeMatch!(ror, return)) // Extra-special specialization: // Why multiple if() allowed? Because it makes the formatting less // of a mess, thus better readability. Good enough reason to me! InputRange join(InputRange!InputRange ror, Type sep) if(unqualTypeMatch!(ror, sep, return)) if(hasLength!typeof(sep)) { /+...take advantage of sep.length...+/ } // Note: Those constraints have further room for syntactical improvement. --------------------------------------------------- That example involves some additional things defined by the stdlib (*extremely* hypothetical syntax): --------------------------------------------------- concept InputRange(Element) { this() { // Current body of isInputRange here } // Most of isInputRange can *optionally* be replaced with: Element front(); void popFront(); bool empty(); } concept ForwardRange : InputRange // Builds upon InputRange { // Author can opt to do this (more powerful): this() { super.this(); typeof(this) x = this.save; } // Or this (more succinct): ForwardRange save(); } // *Anything*: A concrete (instatiable) type, or a templated // stand-in for a type (ie "T"), or an alias, or nothing at all. // Types *themselves* are first-class types! But implemented as // templates, rather than as runtime-OO. algebraic Any : Bottom; // An actual concrete type algrbraic Type : Any if(isType!this); // An actual concrete type? bool isType(Any any) {/+...introspection magic lies here...+/} // This is implicitly a template. bool unqualTypeMatch(InputRange!Any args...) { return args.map!(GetType).map!(Unqual).equal; } // If any is a static type, return any. // If any is a value, return typeof(any) // This is implicitly a template. Type GetType(Any any) { static if(typeof(any) == Type) return any; else return typeof(any); } --------------------------------------------------- Now, something like THAT is the language *I* would love to see. Obviously leaves a TON of details TBD, but one can dream ;)
Jul 09 2017
parent reply Jacob Carlborg <doob me.com> writes:
On 2017-07-10 07:54, Nick Sabalausky (Abscissa) wrote:
   On 07/09/2017 09:21 PM, Nick Sabalausky wrote:
  >
  > Ah, I guess it is very similar after all, except it'd be based on top of
  > and coexist with all of D's design by introspection stuff (rather than
  > exist without it as with C++), thus avoiding a lot of the downsides and
  > getting best of both worlds.
 
 Ha ha, I still feel more than a little silly for pitching what amounts 
 to contracts as "an out-there idea I've been mulling over", but indulge 
 in a little (partially-baked) taste to show this at least has some merit 
 anyway. Hell, call it "concepts++" or "concepts, the D way" (note: I'm 
 NOT pitching this as a suggestion for something D should do. Not saying 
 D should or should'nt, just speaking purely in the realm of "langauge 
 design brainstorming" here...Just because it's been on my mind and the 
 "Why is phobos so wack?" thread brought some relevence)
 
 Behold! The power of combining constraints/design-by-introspection 
 *with* concepts:
 
 Current declaration of std.array.join:
 
 ---------------------------------------------------
 ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror, scope R sep)
 if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && 
 isInputRange!R && is(Unqual!(ElementType!(ElementType!RoR)) == 
 Unqual!(ElementType!R)));
 
 ElementEncodingType!(ElementType!RoR)[] join(RoR, E)(RoR ror, scope E sep)
 if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && is(E 
 : ElementType!(ElementType!RoR)));
 
 ElementEncodingType!(ElementType!RoR)[] join(RoR)(RoR ror)
 if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)));
 ---------------------------------------------------
 
 (ie, completely incomprehensible at-a-glance)
 
 Just one possibility of an entirely hypothetical D++ (assuming I'm even 
 interpreting the D version correctly):
 
 ---------------------------------------------------
 // Note: This assumes the "ElementEncodingType vs ElementType" distinction
 // is nothing but a colossal mistake caused purely by the existance of
 // auto-decoding, which was (as an assumption this psuedo-code is 
 predicated
 // upon) a complete clusterf*** of misdesign (Ie, *such* a huge stretch of
 // the imagination ;)), which in this hypothetical ideal langauge has
 // been killed dead with nuclear fire, and then beaten some more with
 // spiked crowbars, just to be sure.
 
 /++
    Params:
      ror: an input range (or better) of input ranges (or better) of
           any type (shorthand for 'InputRange!InputRange!Type')
      sep: a separator that can be any input range ('InputRange!Type').
    Returns: Shorthand for 'InputRange!Type': Ie, an input range (or 
 better).
    Note: This is implicitly templated on typeof(ror) and typeof(sep).
 +/
 InputRange join(InputRange!InputRange ror, InputRange sep)
    // Relationship constraints:
    if(UnqualTypeMatch!(ror, sep, return))
 
 /++
    Like above, but sep is 'Type' instead of 'InputRange!Type'.
    Since 'Type' is less specific than 'InputRange!Type', the prior overload
    is preferred.
 +/
 InputRange join(InputRange!InputRange ror, Type sep)
    // Relationship constraints:
    if(unqualTypeMatch!(ror, InputRange!sep, return))
 
 // No separator
 InputRange join(InputRange!InputRange ror)
    // Relationship constraints:
    if(unqualTypeMatch!(ror, return))
 
 // Extra-special specialization:
 // Why multiple if() allowed? Because it makes the formatting less
 // of a mess, thus better readability. Good enough reason to me!
 InputRange join(InputRange!InputRange ror, Type sep)
    if(unqualTypeMatch!(ror, sep, return))
    if(hasLength!typeof(sep))
    {  /+...take advantage of sep.length...+/ }
 
 // Note: Those constraints have further room for syntactical improvement.
 ---------------------------------------------------
 
 That example involves some additional things defined by the
 stdlib (*extremely* hypothetical syntax):
 
 ---------------------------------------------------
 concept InputRange(Element)
 {
      this()
      {
          // Current body of isInputRange here
      }
 
      // Most of isInputRange can *optionally* be replaced with:
      Element front();
      void popFront();
      bool empty();
 }
 
 concept ForwardRange : InputRange // Builds upon InputRange
 {
      // Author can opt to do this (more powerful):
      this()
      {
          super.this();
          typeof(this) x = this.save;
      }
 
      // Or this (more succinct):
      ForwardRange save();
 }
 
 // *Anything*: A concrete (instatiable) type, or a templated
 // stand-in for a type (ie "T"), or an alias, or nothing at all.
 // Types *themselves* are first-class types! But implemented as
 // templates, rather than as runtime-OO.
 algebraic Any : Bottom;
 
 // An actual concrete type
 algrbraic Type : Any
      if(isType!this);
 
 // An actual concrete type?
 bool isType(Any any) {/+...introspection magic lies here...+/}
 
 // This is implicitly a template.
 bool unqualTypeMatch(InputRange!Any args...)
 {
      return args.map!(GetType).map!(Unqual).equal;
 }
 
 // If any is a static type, return any.
 // If any is a value, return typeof(any)
 // This is implicitly a template.
 Type GetType(Any any)
 {
      static if(typeof(any) == Type)
          return any;
      else
          return typeof(any);
 }
 ---------------------------------------------------
 
 Now, something like THAT is the language *I* would love to see.
 
 Obviously leaves a TON of details TBD, but one can dream ;)
Something like this has been proposed several times before, but Andrei doesn't seem to like it. He think it's a failure that all the conditions need to have a name, or something like that. I prefer your approach. -- /Jacob Carlborg
Jul 10 2017
parent reply "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
On 07/10/2017 07:32 AM, Jacob Carlborg wrote:
 
 Something like this has been proposed several times before, but Andrei 
 doesn't seem to like it. He think it's a failure that all the conditions 
 need to have a name, or something like that. I prefer your approach.
 
Well, the nice thing about this approach (basing a concept-ish system *on top* of existing D-style design-by-introspection, as opposed to a C++-like concepts with no D-like features to complement it), is that it *doesn't* require every little variation to be named. For example, in the same psuedo-code I posted, there's a function (the last join() overload) that takes an input range, but requires the input range to support hasLength. But notice that there is NO symbol created or used anywhere for InputRangeWithLength. IIUC, it sounds like C++ concepts would require such a symbol to be created. But with this, that would not be needed. One thing to keep in mind is that we're ALREADY creating names for many (not all, but definitely some) of these things. In effect, *every* time we have an 'isXXXXX' function (isSomeString, isForwardRange, etc), we're already creating a name for it. We already implicitly understand that just because it's unrealisting to name *everything* (which, indicentally, reminds me of old Java class hierarchies), doesn't mean we can't or shouldn't name some things. The other important thing I want to emplasize yet again (just in case, because I know from experience in the past it's exactly this kind of point that rarely gets noticed), I'm not proposing D do this. It'd be far too big a change and it's far too incomplete to even think of trying to push. (Even tiny straightforward improvements to D face dowwnright epic levels of resistance any more.) So again, it's just some brainstorming. Maybe D several decades from now, maybe some other language inspired by D, maybe nothing ever, whatever.
Jul 10 2017
parent reply Jacob Carlborg <doob me.com> writes:
On 2017-07-10 19:54, Nick Sabalausky (Abscissa) wrote:

 Well, the nice thing about this approach (basing a concept-ish system
 *on top* of existing D-style design-by-introspection, as opposed to a
 C++-like concepts with no D-like features to complement it), is that it
 *doesn't* require every little variation to be named.

 For example, in the same psuedo-code I posted, there's a function (the
 last join() overload) that takes an input range, but requires the input
 range to support hasLength. But notice that there is NO symbol created
 or used anywhere for InputRangeWithLength. IIUC, it sounds like C++
 concepts would require such a symbol to be created. But with this, that
 would not be needed.

 One thing to keep in mind is that we're ALREADY creating names for many
 (not all, but definitely some) of these things. In effect, *every* time
 we have an 'isXXXXX' function (isSomeString, isForwardRange, etc), we're
 already creating a name for it. We already implicitly understand that
 just because it's unrealisting to name *everything* (which,
 indicentally, reminds me of old Java class hierarchies), doesn't mean we
 can't or shouldn't name some things.
I agree, it's not me that need convincing :)
 The other important thing I want to emplasize yet again (just in case,
 because I know from experience in the past it's exactly this kind of
 point that rarely gets noticed), I'm not proposing D do this. It'd be
 far too big a change and it's far too incomplete to even think of trying
 to push. (Even tiny straightforward improvements to D face dowwnright
 epic levels of resistance any more.) So again, it's just some
 brainstorming. Maybe D several decades from now, maybe some other
 language inspired by D, maybe nothing ever, whatever.
Here I disagree. I think that D should have something like this. -- /Jacob Carlborg
Jul 10 2017
parent reply "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
On 07/10/2017 02:55 PM, Jacob Carlborg wrote:
 On 2017-07-10 19:54, Nick Sabalausky (Abscissa) wrote:
 The other important thing I want to emplasize yet again (just in case,
 because I know from experience in the past it's exactly this kind of
 point that rarely gets noticed), I'm not proposing D do this. It'd be
 far too big a change and it's far too incomplete to even think of trying
 to push. (Even tiny straightforward improvements to D face dowwnright
 epic levels of resistance any more.) So again, it's just some
 brainstorming. Maybe D several decades from now, maybe some other
 language inspired by D, maybe nothing ever, whatever.
Here I disagree. I think that D should have something like this.
Oh, I didn't mean to imply that I wouldn't love to have it in D (assuming it was all well-fleshed out and didn't have big problems). I just wanted to be crystal clear that I'm merely discussing a langauge design idea here rather than coming in saying "Hey, you people should all like this idea and go implement it put it into D!!!" It's easy for things to get taken that way here, and can result in knee-jerk reactions and otherwise derailing of what's really only intended as a theoretical academic discussion. If something *were* to come of it, and it worked great, and everybody was happy, then fantastic. That's just not what I'm bringing it up for, that's all.
Jul 10 2017
parent reply "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
On 07/10/2017 04:14 PM, Nick Sabalausky (Abscissa) wrote:
 
 Oh, I didn't mean to imply that I wouldn't love to have it in D 
 (assuming it was all well-fleshed out and didn't have big problems). I 
 just wanted to be crystal clear that I'm merely discussing a langauge 
 design idea here rather than coming in saying "Hey, you people should 
 all like this idea and go implement it put it into D!!!" It's easy for 
 things to get taken that way here, and can result in knee-jerk reactions 
 and otherwise derailing of what's really only intended as a theoretical 
 academic discussion. If something *were* to come of it, and it worked 
 great, and everybody was happy, then fantastic. That's just not what I'm 
 bringing it up for, that's all.
I especially wanted to avoid any the "How dare you even consider speaking of something without fully implementing it first!" that tends to be common here. (Speaking of, *that* sort of thing is far more unprofessional than the mere "bad words" some people are so terrified of).
Jul 10 2017
parent Jacob Carlborg <doob me.com> writes:
On 2017-07-10 22:19, Nick Sabalausky (Abscissa) wrote:
 On 07/10/2017 04:14 PM, Nick Sabalausky (Abscissa) wrote:
 Oh, I didn't mean to imply that I wouldn't love to have it in D 
 (assuming it was all well-fleshed out and didn't have big problems). I 
 just wanted to be crystal clear that I'm merely discussing a langauge 
 design idea here rather than coming in saying "Hey, you people should 
 all like this idea and go implement it put it into D!!!" It's easy for 
 things to get taken that way here, and can result in knee-jerk 
 reactions and otherwise derailing of what's really only intended as a 
 theoretical academic discussion. If something *were* to come of it, 
 and it worked great, and everybody was happy, then fantastic. That's 
 just not what I'm bringing it up for, that's all.
I especially wanted to avoid any the "How dare you even consider speaking of something without fully implementing it first!" that tends to be common here. (Speaking of, *that* sort of thing is far more unprofessional than the mere "bad words" some people are so terrified of).
Fair enough. -- /Jacob Carlborg
Jul 10 2017
prev sibling next sibling parent reply bpr <brogoff gmail.com> writes:
On Monday, 10 July 2017 at 01:21:08 UTC, Nick Sabalausky wrote:
 Ah, I guess it is very similar after all, except it'd be based 
 on top of and coexist with all of D's design by introspection 
 stuff (rather than exist without it as with C++), thus avoiding 
 a lot of the downsides and getting best of both worlds.
You've seen this, right? https://wiki.dlang.org/User:9rnsr/DIP:_Template_Parameter_Constraint A small step in one such direction, influenced by C++ concepts. That proto-DIP also raises a question I always had about why D doesn't allow chained template instantiation, but that's another DIP for another time.
Jul 10 2017
parent "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
On 07/10/2017 11:58 AM, bpr wrote:
 
 You've seen this, right?
 
 https://wiki.dlang.org/User:9rnsr/DIP:_Template_Parameter_Constraint
 
 A small step in one such direction, influenced by C++ concepts. That 
 proto-DIP also raises a question I always had about why D doesn't allow 
 chained template instantiation, but that's another DIP for another time.
 
Yea, I've seen that. It'd be a nice improvent for D and I'm definitely in favor of it. It doesn't especially excite me though just because it's a small incremental change and creates further syntactical differences between handling runtime-oriented symbols and compile-time-oriented symbols. Ie, I'd prefer "InputRange r" over "T r if InputRange" because it's vastly simpler and more consistent with non-templated variable declarations. But in a practical sense, that's be a much more major and difficult to retrofit that onto D, so the DIP sounds like an appropriate (if unexciting) direction for D to take. But what I find much more interesting than that DIP (again, from a purely academic standpoint) is taking all of these abilities and finding a way simplify them, while retaining all of their power, and create more overall consistency[1]. (That was *exactly* one of my big original draws to D in the first place - it took C++, then cleaned it all up and enhanced it. I have interest in brainstorming the same for D. I think there's been enough practical experience using D at this point for more streamlined designs to now be possible.) [1] Heck, on the consistency front, it even bugs the hell out of me when people do "foo()" to call/define a function, but then deliberately stick with "if ()"-style instead for keywords. Both are "identifier followed by parens", but whether or not a space is added between is *different* depending on whether the identifier is a symbol or a keyword. Unnecessary inconsistency. Maybe it's all the puzzle games I've played over my lifetime, but...want...to...simplify... ;)
Jul 10 2017
prev sibling next sibling parent bpr <brogoff gmail.com> writes:
On Monday, 10 July 2017 at 01:21:08 UTC, Nick Sabalausky wrote:
 Ah, I guess it is very similar after all, except it'd be based 
 on top of and coexist with all of D's design by introspection 
 stuff (rather than exist without it as with C++), thus avoiding 
 a lot of the downsides and getting best of both worlds.
You've seen this, right? https://wiki.dlang.org/User:9rnsr/DIP:_Template_Parameter_Constraint A small step in one such direction, influenced by C++ concepts. That proto-DIP also raises a question I always had about why D doesn't allow chained template instantiation, but that's another DIP for another time.
Jul 10 2017
prev sibling parent reply bpr <brogoff gmail.com> writes:
On Monday, 10 July 2017 at 01:21:08 UTC, Nick Sabalausky wrote:
 Ah, I guess it is very similar after all, except it'd be based 
 on top of and coexist with all of D's design by introspection 
 stuff (rather than exist without it as with C++), thus avoiding 
 a lot of the downsides and getting best of both worlds.
You've seen this, right? https://wiki.dlang.org/User:9rnsr/DIP:_Template_Parameter_Constraint A small step in one such direction, influenced by C++ concepts. That proto-DIP also raises a question I always had about why D doesn't allow chained template instantiation, but that's another DIP for another time.
Jul 10 2017
parent bpr <brogoff gmail.com> writes:
On Monday, 10 July 2017 at 16:16:40 UTC, bpr wrote:
 On Monday, 10 July 2017 at 01:21:08 UTC, Nick Sabalausky wrote:
 Ah, I guess it is very similar after all, except it'd be based 
 on top of and coexist with all of D's design by introspection 
 stuff (rather than exist without it as with C++), thus 
 avoiding a lot of the downsides and getting best of both 
 worlds.
You've seen this, right? https://wiki.dlang.org/User:9rnsr/DIP:_Template_Parameter_Constraint A small step in one such direction, influenced by C++ concepts. That proto-DIP also raises a question I always had about why D doesn't allow chained template instantiation, but that's another DIP for another time.
Sorry about the repeat posting, I could observe the software hiccuping on my browser...
Jul 10 2017
prev sibling next sibling parent reply Martin Nowak <code dawg.eu> writes:
On Sunday, 9 July 2017 at 20:22:16 UTC, Nick Sabalausky 
(Abscissa) wrote:
 SomeString fizzbar(RandomAccessRange!SomeNumeric r) {...}
Looks like concepts. We've settled on leveraging the already useful template constraints (at best in CNF [¹]) for better error messages. It's on the Agenda for later this year [²]. [¹]: https://github.com/dlang/phobos/pull/5461 [²]: https://wiki.dlang.org/Vision/2017H2_draft
Jul 10 2017
parent "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
On 07/10/2017 09:16 AM, Martin Nowak wrote:
 On Sunday, 9 July 2017 at 20:22:16 UTC, Nick Sabalausky (Abscissa) wrote:
 SomeString fizzbar(RandomAccessRange!SomeNumeric r) {...}
Looks like concepts. We've settled on leveraging the already useful template constraints (at best in CNF [¹]) for better error messages. It's on the Agenda for later this year [²]. [¹]: https://github.com/dlang/phobos/pull/5461 [²]: https://wiki.dlang.org/Vision/2017H2_draft
Sounds nice. But I'm getting the distinct impression people are missing that I never actually proposed that D itself should do this. It's just academic brainstorming.
Jul 10 2017
prev sibling next sibling parent bpr <brogoff gmail.com> writes:
On Sunday, 9 July 2017 at 20:22:16 UTC, Nick Sabalausky 
(Abscissa) wrote:
 Obviously this is all very incomplete, but it's an idea I think 
 is rather interesting.
You've seen this, right? https://wiki.dlang.org/User:9rnsr/DIP:_Template_Parameter_Constraint A small step in one such direction, influenced by C++ concepts. That proto-DIP also raises a question I always had about why D doesn't allow chained template instantiation, but that's another DIP for another time.
Jul 10 2017
prev sibling next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sun, 9 Jul 2017 16:22:16 -0400
schrieb "Nick Sabalausky (Abscissa)"
<SeeWebsiteToContactMe semitwist.com>:

 [=E2=80=A6] a sufficiently-smart compiler could conceivably even
 choose "runtime" vs "compile-time" (or even, "it varies")
 based on optimization priorities.
GCC already does this, i.e. find runtime arguments of constant value and generate a second instance of the function with that argument optimized out. --=20 Marco
Jul 10 2017
prev sibling parent Mark <smarksc gmail.com> writes:
On Sunday, 9 July 2017 at 20:22:16 UTC, Nick Sabalausky 
(Abscissa) wrote:
 So, why not encapsulate much of that stuff we merely *describe* 
 in signatures for generic functions into genuine 
 honest-to-goodness types?

 There would be user-defined symbols, such as "InputRange" or 
 "SomeString", or "RandomAccessRange!SomeString", which the type 
 system sees as actual types. And naturally there would be some 
 mechanism for actually defining those types. Then, defining a 
 function like this:

 SomeString fizzbar(RandomAccessRange!SomeNumeric r) {...}

 ...would automatically imply to the compiler all (or at least a 
 lot of) the pluming we usually clutter the function declaration 
 with: Defining the templated types and calling the appropriate 
 if(isBlahBlah) constraints. About the only things remaining 
 would be additional constraints not already defined by the 
 next-gen types, and restrictions on how the parameters relate 
 to each other.

 Even better, having all that encapsulated into genuine types 
 should make it easier for the compiler to provide better error 
 messages.
This reminds me of the "RAII vs. scope" arguments that came up on the forum a few times (see e.g. [1]). Many of the features in D (and other programming languages) can be theoretically (and practically, in some languages) implemented using the type system: resource management, template constraints, in/out contracts, function attributes (pure, nothrow, etc.), I/O streams, error handling, and probably others. This is sometimes profitable and sometimes not so much. If you're using some concept all over your code then encapsulating it in a type can reduce code duplication, improve readability and let you exploit various features of the type system to your benefit (e.g. subtyping: A RandomAccessRange being a subtype of InputRange, exception hierarchies, etc.). But if you're only using it once or twice then it's probably not worth the hassle. That is, the issue is scale. My general impression is that C++ tries (and often succeeds, pyrrhically) to do pretty much everything using the type system (specifically, classes): Resources, exceptions, iterators, interfaces, initialization lists, ... Almost everything is encapsulated in a type. Concepts (Lite) seem to me like a way to further enrich the type system, although concepts aren't exactly types. My opinion, in a nutshell, is that "ad-hocish" facilities like template constraints, the scope statement, contracts, etc. don't scale up, while more formal facilities like concepts, RAII, etc. don't scale *down*. As such, there is a need for both of them. With respect to the specific issue of ranges, I don't know Phobos well enough to have an opinion as to whether or not they should be made more formal (as types/concepts/...). The error messages should be more clear and precise, but I'm not convinced that an overhaul of the system is necessary to achieve that. [1] https://forum.dlang.org/post/tlsrpqvfeepcfbyfqzge forum.dlang.org
Jul 15 2017