Thread overview
RT/CT Type
Apr 02, 2019
Alex
Apr 02, 2019
Dennis
Apr 02, 2019
Jacob Carlborg
Apr 02, 2019
Alex
Apr 02, 2019
Paul Backus
Apr 02, 2019
pham
Apr 02, 2019
Bastiaan Veelo
[OT] Delphi class type
Apr 02, 2019
Bastiaan Veelo
April 02, 2019
Since D has a highly evolved meta programming and it should have unitifed type that works two ways:

1. At CT, the type acts as an type or sorta like an alias.
2. At RT the type acts as a string.

Type t = int;

At compile time,

t x;

is the same at

int x;


At RT t = "int"


Why is this important?


The purpose is to unify certain CT and RT code. Because CTFE acts as runtime we might use it to build a type, but as a string, such as

return getType(T)(T x)
{
    return T.stringof; // CTFE/RT
    //return T // would be simpler
}

But then we could do

getType(32) x;

at CT.

or use getType at runtime.

This is a contrived example but I'm finding that I'm having to use CTFE to deal with types which requires strings and then convert those strings back in to types using string mixins, which is a PIBA.









April 02, 2019
Interesting idea. I heard Stefan Koch was working on a DIP for first class types in D, you might be interested in that. I also know Zig has a 'comptime' keyword and first class types to do meta programming, which removes the explicit distinction between RT/CT parameter lists that D has.

On Tuesday, 2 April 2019 at 07:48:23 UTC, Alex wrote:
> This is a contrived example but I'm finding that I'm having to use CTFE to deal with types which requires strings and then convert those strings back in to types using string mixins, which is a PIBA.

Can you give your actual usecase? Your example is already doable with typeof().
April 02, 2019
On 2019-04-02 09:48, Alex wrote:
> Since D has a highly evolved meta programming and it should have unitifed type that works two ways:
> 
> 1. At CT, the type acts as an type or sorta like an alias.
> 2. At RT the type acts as a string.
> 
> Type t = int;
> 
> At compile time,
> 
> t x;
> 
> is the same at
> 
> int x;
> 
> 
> At RT t = "int"
> 
> 
> Why is this important?
> 
> 
> The purpose is to unify certain CT and RT code. Because CTFE acts as runtime we might use it to build a type, but as a string, such as
> 
> return getType(T)(T x)
> {
>      return T.stringof; // CTFE/RT
>      //return T // would be simpler
> }
> 
> But then we could do
> 
> getType(32) x;
> 
> at CT.
> 
> or use getType at runtime.
> 
> This is a contrived example but I'm finding that I'm having to use CTFE to deal with types which requires strings and then convert those strings back in to types using string mixins, which is a PIBA.

I would much rather that D had first class types. That is, it would be possible to store types in variables and in arrays and so on.

-- 
/Jacob Carlborg
April 02, 2019
On Tuesday, 2 April 2019 at 10:45:37 UTC, Jacob Carlborg wrote:
> On 2019-04-02 09:48, Alex wrote:
>> Since D has a highly evolved meta programming and it should have unitifed type that works two ways:
>> 
>> 1. At CT, the type acts as an type or sorta like an alias.
>> 2. At RT the type acts as a string.
>> 
>> Type t = int;
>> 
>> At compile time,
>> 
>> t x;
>> 
>> is the same at
>> 
>> int x;
>> 
>> 
>> At RT t = "int"
>> 
>> 
>> Why is this important?
>> 
>> 
>> The purpose is to unify certain CT and RT code. Because CTFE acts as runtime we might use it to build a type, but as a string, such as
>> 
>> return getType(T)(T x)
>> {
>>      return T.stringof; // CTFE/RT
>>      //return T // would be simpler
>> }
>> 
>> But then we could do
>> 
>> getType(32) x;
>> 
>> at CT.
>> 
>> or use getType at runtime.
>> 
>> This is a contrived example but I'm finding that I'm having to use CTFE to deal with types which requires strings and then convert those strings back in to types using string mixins, which is a PIBA.
>
> I would much rather that D had first class types. That is, it would be possible to store types in variables and in arrays and so on.

Sure, but that isn't likely to happen and probably will be far more work. By simply having them convert to strings in RT helps a lot. When combined with CTFE and mixins it works well because one can go back and forth between type and strings.


April 02, 2019
On 4/2/19 8:38 AM, Alex wrote:
> Sure, but that isn't likely to happen and probably will be far more work. By simply having them convert to strings in RT helps a lot. When combined with CTFE and mixins it works well because one can go back and forth between type and strings.

You cannot, in the general case, go back and forth freely between types and strings using `mixin`. Converting a type to a string discards all of its context information, and there is no way to recover that information from the string alone.

Example: https://run.dlang.io/is/EAzKUC

Even if this particular issue were fixed (getType could return a fully-qualified name), there would still be the issue of Voldemort types, which can *never* be mixed-in, even with a fully-qualified name.
April 02, 2019
On Tuesday, 2 April 2019 at 10:45:37 UTC, Jacob Carlborg wrote:
> On 2019-04-02 09:48, Alex wrote:
>> Since D has a highly evolved meta programming and it should have unitifed type that works two ways:
>> 

>> 
>> This is a contrived example but I'm finding that I'm having to use CTFE to deal with types which requires strings and then convert those strings back in to types using string mixins, which is a PIBA.
>
> I would much rather that D had first class types. That is, it would be possible to store types in variables and in arrays and so on.

Delphi has implemented class type for a long time. D should have vision to implement it. However, D also needs to implement inherited constructor in order for it to work

Skeleton sample in Delphi

type
A = class
  create() virtual  // constructor
    writeln('A.create')

B = class(A)
  create() override // constructor
    //inherited create() // call inherited constructor implement if needed
    writeln('B.create')

ClassType = class of A; // Any class inherited from A can be used to set to this type


ClassType x = A;
var x1 = x.create()  // output 'A.create'
x = B
x1 = x.create()  // output 'B.create'

Cheers
Pham


April 02, 2019
On Tuesday, 2 April 2019 at 17:00:41 UTC, pham wrote:
> On Tuesday, 2 April 2019 at 10:45:37 UTC, Jacob Carlborg wrote:
>> I would much rather that D had first class types. That is, it would be possible to store types in variables and in arrays and so on.
>
> Delphi has implemented class type for a long time. D should have vision to implement it. However, D also needs to implement inherited constructor in order for it to work
>
> Skeleton sample in Delphi
>
> type
> A = class
>   create() virtual  // constructor
>     writeln('A.create')
>
> B = class(A)
>   create() override // constructor
>     //inherited create() // call inherited constructor implement if needed
>     writeln('B.create')
>
> ClassType = class of A; // Any class inherited from A can be used to set to this type
>
>
> ClassType x = A;
> var x1 = x.create()  // output 'A.create'
> x = B
> x1 = x.create()  // output 'B.create'
>
> Cheers
> Pham

Jacob is talking about "first class" types. D does support classes just like Delphi does (https://dlang.org/spec/class.html):

----
If no call to constructors via this or super appear in a constructor, and the base class has a constructor, a call to super() is inserted at the beginning of the constructor.

If there is no constructor for a class, but there is a constructor for the base class, a default constructor is implicitly generated with the form:

this() { }
----

April 02, 2019
On Tuesday, 2 April 2019 at 17:00:41 UTC, pham wrote:
[...]
> Skeleton sample in Delphi
>
> type
> A = class
>   create() virtual  // constructor
>     writeln('A.create')
>
> B = class(A)
>   create() override // constructor
>     //inherited create() // call inherited constructor implement if needed
>     writeln('B.create')
>
> ClassType = class of A; // Any class inherited from A can be used to set to this type
>
>
> ClassType x = A;
> var x1 = x.create()  // output 'A.create'
> x = B
> x1 = x.create()  // output 'B.create'

So in Delphi you can skip calling the constructor of the base class if you omit `inherited create()`? That would be rather odd. D does the right thing:

---
import std.stdio;

class A
{
    this() { writeln(__FUNCTION__); }
}

class B : A
{
    this() { writeln(__FUNCTION__); }
}

void main()
{
    A a = new A; // Output A.this
    a = new B;   // Output A.this, B.this.
}
---
https://run.dlang.io/is/6b2T4D


Bastiaan.