Types: The Next Generation (Was: Why is phobos so wack?)
Jacob Carlborg via Digitalmars-d
digitalmars-d at puremagic.com
Mon Jul 10 04:32:20 PDT 2017
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
More information about the Digitalmars-d
mailing list