www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Derived type

reply novice3 <sorryno em.ail> writes:
Hello.

When i adapt C code, i see new type creation:
   typedef void* Xobj;

Or code like this:
   struct _Xobj;
   typedef struct _Xobj *Xobj;


I want create derived type in D, found std.typecons.Typedef 
template, and write:
   alias Xobj = Typedef!(void*, (void*).init);

But compiler use long type name in error messages, like this:

   Error: function test6.foo(Typedef!(void*, null, null) obj) is 
not callable using argument types (void*)

   cannot pass argument bad of type void* to parameter 
Typedef!(void*, null, null) obj

This messages dont help me understand, which type should i use.
What i should change?
Or Typedef template should be changes?
Any Typedef alternatives?
Mar 30 2021
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Tuesday, 30 March 2021 at 13:28:55 UTC, novice3 wrote:

 This messages dont help me understand, which type should i use.
 What i should change?
 Or Typedef template should be changes?
From the docs: "Unlike the alias feature, Typedef ensures the two types are not considered as equals. Parameters:" https://dlang.org/phobos/std_typecons.html#Typedef
 Any Typedef alternatives?
If you want your new type to be interchangeable with another, the straightforward way is just to use an alias. Buf if you need a more concrete type, you can use alias this in a struct: import std.stdio; struct MyType { void* wrapped; alias wrapped this; } void doSomething(void* t) { writeln(*(cast(int*)t)); } void main() { int i = 20; MyType mt = MyType(&i); doSomething(mt); }
Mar 30 2021
parent reply novice2 <sorryno em.ail> writes:
On Tuesday, 30 March 2021 at 13:43:52 UTC, Mike Parker wrote:
 the straightforward way is just to use an alias.
i cant use alias - compiler cannot distinguish base type and alias, and cannot catch programmer errors
 Buf if you need a more concrete type, you can use alias this in 
 a struct:
I think Typedef template should do this struct for me. Thanks Mike, this way is what i wanted struct Xobj { private void* payload; alias payload this; } Xobj good; foo(good); //nice foo(cast(Xobj)null); //explicit cast allowed - nice foo(null); //no implicit cast disallowed - compiler error - nice void* bad; foo(bad); //compiler distinguish type - error - nice I think Typedef template should do this struct for me. Problem with Typedef template - code alias Xobj = Typedef!(void*) not generate struct named "Xobj", but struct named "Typedef!(void*, null, null)". This makes compiler error messages unusable. I will try to make template for struct. But template is black magic for me :)
Mar 30 2021
parent reply novice2 <sorryno em.ail> writes:
My tries to make template for struct and alias this:

////// variant 1
template Typedef(alias Tnew, Tbase)
{
   struct Tnew
   {
     Tbase payload;
     alias payload this;
   }
}

Typedef!(Xobj, void*);

void foo (Xobj obj) {}  //compiler Error: no identifier for 
declarator Typedef!(Xobj, void*)


////// variant 2
mixin template Typedef(alias Tnew, Tbase)
{
   struct Tnew
   {
     Tbase payload;
     alias payload this;
   }
}

mixin Typedef!(Xobj, void*);  //compiler Error: undefined 
identifier Xobj
Mar 30 2021
parent reply Basile B. <b2.temp gmx.com> writes:
On Tuesday, 30 March 2021 at 19:47:41 UTC, novice2 wrote:
 My tries to make template for struct and alias this:

 ////// variant 1
 template Typedef(alias Tnew, Tbase)
 {
   struct Tnew
   {
     Tbase payload;
     alias payload this;
   }
 }
you must give a name to the template specialization, using alias [1], also the TypeDef declaration can be highly simplified: --- struct Typedef(TBase) { TBase payload; alias payload this; } alias Xobj = Typedef!(void*); void foo (Xobj obj) {} --- [1]: https://dlang.org/spec/declaration.html#alias
Mar 30 2021
parent reply novice3 <sorryno em.ail> writes:
On Tuesday, 30 March 2021 at 21:53:34 UTC, Basile B. wrote:
 struct Typedef(TBase)
 {
    TBase payload;
    alias payload this;
 }

 alias Xobj = Typedef!(void*);
This is how std.typecons.Typedef made, IMHO. The problem is this code generate struct with name "Typedef!(void*)", then compiler show this name (not "Xobj") in messages: https://run.dlang.io/is/eEI2yC void* bad; foo(bad); Error: function foo(Typedef!(void*) obj) is not callable using argument types (void*) cannot pass argument bad of type void* to parameter Typedef!(void*) obj
Mar 30 2021
parent reply Basile B. <b2.temp gmx.com> writes:
On Wednesday, 31 March 2021 at 04:49:50 UTC, novice3 wrote:
 On Tuesday, 30 March 2021 at 21:53:34 UTC, Basile B. wrote:
 struct Typedef(TBase)
 {
    TBase payload;
    alias payload this;
 }

 alias Xobj = Typedef!(void*);
This is how std.typecons.Typedef made, IMHO. The problem is this code generate struct with name "Typedef!(void*)", then compiler show this name (not "Xobj") in messages: https://run.dlang.io/is/eEI2yC void* bad; foo(bad); Error: function foo(Typedef!(void*) obj) is not callable using argument types (void*) cannot pass argument bad of type void* to parameter Typedef!(void*) obj
yeah template instances are identified using the parameters identifiers, then the alias is just a syntactic shortcut to that, not producing a new symbol with a unique mangle... but the message is correct assuming you want void* to be rejected. That being said you can still use a string mixin if the messages have to be correct --- string genTypeDef(TBase)(string name) { return "struct " ~ name ~ "{" ~ TBase.stringof ~ " payload; alias payload this;}"; } mixin(genTypeDef!(void*)("Xobj")); void foo (Xobj obj) {} ---
Mar 31 2021
parent novice3 <sorryno em.ail> writes:
On Wednesday, 31 March 2021 at 12:09:33 UTC, Basile B. wrote:
 yeah template instances are identified using the parameters 
 identifiers, then the alias is just a syntactic shortcut to 
 that, not producing a new symbol with a unique mangle...
so, no way to generate struct with parametrized name by template or mixin template?
 That being said you can still use a string mixin if the 
 messages have to be correct
 ...
thank you!
Mar 31 2021
prev sibling next sibling parent reply WebFreak001 <d.forum webfreak.org> writes:
On Tuesday, 30 March 2021 at 13:28:55 UTC, novice3 wrote:
 Hello.

 When i adapt C code, i see new type creation:
   typedef void* Xobj;

 Or code like this:
   struct _Xobj;
   typedef struct _Xobj *Xobj;


 I want create derived type in D, found std.typecons.Typedef 
 template, and write:
   alias Xobj = Typedef!(void*, (void*).init);

 But compiler use long type name in error messages, like this:

   Error: function test6.foo(Typedef!(void*, null, null) obj) is 
 not callable using argument types (void*)

   cannot pass argument bad of type void* to parameter 
 Typedef!(void*, null, null) obj

 This messages dont help me understand, which type should i use.
 What i should change?
 Or Typedef template should be changes?
 Any Typedef alternatives?
The typedef in C in D is just an alias: ``` alias Xobj = void*; ``` Xobj can then be used interchangeably with void*, so all void* arguments accept Xobj and all Xobj arguments accept void*. If you want a type-safe alias that makes all void* arguments accept Xobj but not Xobj arguments to accept void* you can use `Typedef` like you linked. However using this language built-in feature is much simpler and cheaper in terms of resource usage and compile time + always results in the fastest code: (there is no conversions at all) ``` enum Xobj : void*; ``` This allows explicit conversion in both ways using cast, but only allows implicit conversion from Xobj to void*, not from void* to Xobj: ``` void* x = someValue; Xobj y = cast(Xobj)x; // ok x = y; // ok y = x; // error (need explicit cast) ```
Mar 30 2021
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Tuesday, 30 March 2021 at 14:45:12 UTC, WebFreak001 wrote:

 When i adapt C code, i see new type creation:
 The typedef in C in D is just an alias:

 ```
 alias Xobj = void*;
 ```
I totally overlooked the part about porting from C. Yes, this is the way to go in that case.
Mar 30 2021
prev sibling parent reply novice2 <sorryno em.ail> writes:
On Tuesday, 30 March 2021 at 14:45:12 UTC, WebFreak001 wrote:
 Xobj can then be used interchangeably with void*, so all void* 
 arguments accept Xobj and all Xobj arguments accept void*.
yes, i understand alias, and i dont want such behaviour
 If you want a type-safe alias that makes all void* arguments 
 accept Xobj but not Xobj arguments to accept void*
yes, this is that i search
 you can use `Typedef` like you linked.
Problem with Typedef template - code alias Xobj = Typedef!(void*) not generate type named "Xobj", but type named "Typedef!(void*, null, null)". This makes compiler error messages unusable.
 enum Xobj : void*;
 ```
 This allows explicit conversion in both ways using cast, but 
 only allows implicit conversion from Xobj to void*, not from 
 void* to Xobj:
Strange syntax. Behavour exactly what i want, but this code not works for me :( enum Xobj : void*; Xobj var; //DMD Error: enum test7.Xobj forward reference of Xobj.init
Mar 30 2021
parent reply WebFreak001 <d.forum webfreak.org> writes:
On Tuesday, 30 March 2021 at 19:02:09 UTC, novice2 wrote:
 [...]

 Strange syntax.
 Behavour exactly what i want, but this code not works for me :(

   enum Xobj : void*;
   Xobj var;  //DMD Error: enum test7.Xobj forward reference of 
 Xobj.init
You can add a custom init value if you want to allow one: ```d enum Xobj : void* { init = null } ```
Apr 01 2021
parent reply novice3 <sorryno em.ail> writes:
On Thursday, 1 April 2021 at 12:07:17 UTC, WebFreak001 wrote:
 You can add a custom init value if you want to allow one:

 ```d
 enum Xobj : void* { init = null }
 ```
Thank you!
Apr 01 2021
parent novice2 <sorryno em.ail> writes:
thanks, i tried 2 variants:
```d
struct Tnew {TBase payload; alias payload this;}
```
```d
enum Tnew : Tbase {init = Tbase.init}
```

both works, but 1-st not allow "2 level" cast:
```d
struct Xptr {void* payload; alias payload this;} //Xptr based on 
void*
struct Xobj {Xptr payload; alias payload this;}  //Xobj based on  
Xptr
Xptr xptr = cast(Xptr) null;             //OK
Xobj xobj = cast(Xobj) null;             //ERROR
Xobj xobj = cast(Xobj) cast(Xptr) null;  //OK, needs both levels 
explitity
```
```d
enum Xptr : void* {init = (void*).init} //Xptr based on void*
enum Xobj : Xptr {init = Xptr.init}     //Xobj based on  Xptr
Xptr xptr = cast(Xptr) null;            //OK
Xobj xobj = cast(Xobj) null;            //OK
```

so "enum" variant is better for me, thanks!
Apr 01 2021
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 3/30/21 6:28 AM, novice3 wrote:

 I want create derived type in D
"Derived type" is used in the context of object oriented programming at least in D but your examples indicate you need something else. How about the 'alias this' feature? import std.stdio; struct Xobj { void* value; alias value this; } void main() { int i; auto var = Xobj(&i); writeln(var); int j; var = &j; } alias this is for implicit conversions, from Xobj to void* in this case. Ali
Mar 30 2021
parent reply novice2 <sorryno em.ail> writes:
On Tuesday, 30 March 2021 at 19:12:29 UTC, Ali Çehreli wrote:
 "Derived type" is used in the context of object oriented 
 programming at least in D
Sorry, i use wrong termin. I just want create new type Tnew, based on exist type Tbase. Tnew have same allowed values, same properties, same allowed operations as Tbase. Compiler should distinguish New from Tbase. Allowed implicit cast Tnew to Tbase. Prohibited implicit cast Tbase to Tnew. Allowed exlicit cast Tbase to Tnew.
 but your examples indicate you need something else. How about 
 the 'alias this' feature?
Thanks, this is what i want. I just think that Typedef do it for me, hide this boilerplait code.
Mar 30 2021
parent Mike Parker <aldacron gmail.com> writes:
On Tuesday, 30 March 2021 at 19:33:31 UTC, novice2 wrote:
 On Tuesday, 30 March 2021 at 19:12:29 UTC, Ali Çehreli wrote:
 "Derived type" is used in the context of object oriented 
 programming at least in D
Sorry, i use wrong termin. I just want create new type Tnew, based on exist type Tbase. Tnew have same allowed values, same properties, same allowed operations as Tbase. Compiler should distinguish New from Tbase. Allowed implicit cast Tnew to Tbase. Prohibited implicit cast Tbase to Tnew. Allowed exlicit cast Tbase to Tnew.
That's precisely what the alias this feature is intended to do. https://dlang.org/spec/class.html#alias-this
 Thanks, this is what i want.
 I just think that Typedef do it for me, hide this boilerplait 
 code.
That's not the intended purpose of the Typedef template. Its documentation explicitly says it "allows the creation of a unique type which is based on an existing type". The keyword there is *unique*.
Mar 30 2021