Types: The Next Generation (Was: Why is phobos so wack?)

Nick Sabalausky (Abscissa) via Digitalmars-d digitalmars-d at puremagic.com
Sun Jul 9 22:54:08 PDT 2017


  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 ;)



More information about the Digitalmars-d mailing list