www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Is typedef an alien?

reply Aenigmatic <procode adam-dott-com.au> writes:
No further response to any responses to my previous post's responses is a both
swift and non-invasive.

Now my deeply thought question is ...

Is typedef (in D) a C/C++ legacy or is the dear orphan now adopted as a
first-class citizen in the US of D?

-- Yours truly, Justin Johansson
Sep 24 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Aenigmatic:

Is typedef (in D) a C/C++ legacy or is the dear orphan now adopted as a
first-class citizen in the US of D? -- Yours truly, Justin Johansson<

The semantics of D typedef comes from Pascal, not from C. It's useful, but unfortunately it's not a true first-class feature in D, its purposes are mostly pre-OOP. You can use it for example to pass a type-specific fixed-size matrix to several functions, and for similar purposes. Not-ex-Pascal programmers may find it less useful (as nested functions). I'd even like to have Pascal-inspired ranged integral values in D :-) int (1 .. 20) x; They give some safety, and in the wild I've already seen D code like: int foo; // values 0 .. 20 (There are several modern ways to generalize this idea of the type system, but in many programs such integral ranges are enough). Often the comments you can find in programs written in old languages can be written as annotations and syntax in modern languages. Generally it's good to have a syntax to tell the compiler some of the semantics you want to put into the comments. Bye, bearophile
Sep 24 2009
parent bearophile <bearophileHUGS lycos.com> writes:
 I'd even like to have Pascal-inspired ranged integral values in D :-)

Once structs in D2 become flexible enough (with methods like opBool that get called by if(x){}, etc) they can be used to define such ranged integer. I think this flexibility improvement is a better strategy. Bye, bearophile
Sep 24 2009
prev sibling next sibling parent reply language_fan <foo bar.com.invalid> writes:
Thu, 24 Sep 2009 14:36:01 -0400, Aenigmatic thusly wrote:

 No further response to any responses to my previous post's responses is
 a both swift and non-invasive.
 
 Now my deeply thought question is ...
 
 Is typedef (in D) a C/C++ legacy or is the dear orphan now adopted as a
 first-class citizen in the US of D?
 
 -- Yours truly, Justin Johansson

Typedef works differently in D. It should create a new type, in C++ it's just a type synonym.
Sep 24 2009
parent Jeremie Pelletier <jeremiep gmail.com> writes:
language_fan wrote:
 Thu, 24 Sep 2009 14:36:01 -0400, Aenigmatic thusly wrote:
 
 No further response to any responses to my previous post's responses is
 a both swift and non-invasive.

 Now my deeply thought question is ...

 Is typedef (in D) a C/C++ legacy or is the dear orphan now adopted as a
 first-class citizen in the US of D?

 -- Yours truly, Justin Johansson

Typedef works differently in D. It should create a new type, in C++ it's just a type synonym.

Exactly, it's most useful to create specialized types from primitives. For example I declared the HANDLE type in my win32 bindings as "typedef const(void)* HANDLE;" and all its specialized types (HWND, HMONITOR, HDC, etc) are also typedefs of HANDLE, so I have very little chances of misusing them. The only downside is that I must use HWND.init instead of null, but that's just giving better readability to function calls. This is something you just can't do in C.
Sep 24 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 24 Sep 2009 14:36:01 -0400, Aenigmatic <procode adam-dott-com.au>  
wrote:

 No further response to any responses to my previous post's responses is  
 a both swift and non-invasive.

 Now my deeply thought question is ...

 Is typedef (in D) a C/C++ legacy or is the dear orphan now adopted as a  
 first-class citizen in the US of D?

 -- Yours truly, Justin Johansson

typedef is different from alias -- but has some issues. typedef creates a new *incompatible* type. By incompatible, I mean that it doesn't implicitly cast back to the type you created it from. e.g.: typedef int mytype; mytype x; int y = x; // ok, mytype implicitly casts to x x = y; // error, can't implicitly cast. typedef is a distinct type, so it can be used to overload a function: foo(mytype m); foo(int i); mytype x; foo(x); // calls foo(mytype) version You can also set the default value different from the original type: typedef int mytype=5; mytype x; // set to 5. However, there are issues, such as operations don't "just work." i.e.: mytype x = 5; mytype y = x + 5; // error, x + 5 results in an int! Need a cast My experience is that 99% of the time, alias is what you want. I haven't yet encountered a good case for using typedef. But it's abilities certainly are not covered by any other construct, so I'd say it's a first class citizen. -Steve
Sep 24 2009
prev sibling next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Thu, Sep 24, 2009 at 2:36 PM, Aenigmatic <procode adam-dott-com.au> wrote:
 No further response to any responses to my previous post's responses is a both
swift and non-invasive.

 Now my deeply thought question is ...

 Is typedef (in D) a C/C++ legacy or is the dear orphan now adopted as a
first-class citizen in the US of D?

It's a different beast, and in my experience, pretty useless. Most of the time you want typedef'ed types to interact with other types a little more richly. Say you want to use a double as a time. Okay, what do you get when you subtract two points in time? Not a time, that's for sure. You get a time _span_ instead. So you end up implementing them as structs. Virtually every time I've tried to use typedef, it hasn't sufficed and I've ended up using a struct instead. It seems like a failed idea, or at the very least, yet another half-thought-out abandoned feature.
Sep 24 2009
prev sibling next sibling parent language_fan <foo bar.com.invalid> writes:
Thu, 24 Sep 2009 15:33:38 -0400, Jarrett Billingsley thusly wrote:

 On Thu, Sep 24, 2009 at 2:36 PM, Aenigmatic <procode adam-dott-com.au>
 wrote:
 No further response to any responses to my previous post's responses is
 a both swift and non-invasive.

 Now my deeply thought question is ...

 Is typedef (in D) a C/C++ legacy or is the dear orphan now adopted as a
 first-class citizen in the US of D?

It's a different beast, and in my experience, pretty useless. Most of the time you want typedef'ed types to interact with other types a little more richly. Say you want to use a double as a time. Okay, what do you get when you subtract two points in time? Not a time, that's for sure. You get a time _span_ instead. So you end up implementing them as structs. Virtually every time I've tried to use typedef, it hasn't sufficed and I've ended up using a struct instead. It seems like a failed idea, or at the very least, yet another half-thought-out abandoned feature.

I can imagine some uses for it when the type is very simple, and you fear that the compiler cannot inline operations on structs. Other than that, common mainstream language features like typedefs, variant!(), and enums are mere special cases of algebraic datatypes (with some implicit syntactic sugar). There are some downsides, too, but I prefer to have the more general type in languages that I use.
Sep 24 2009
prev sibling next sibling parent language_fan <foo bar.com.invalid> writes:
Thu, 24 Sep 2009 19:44:09 +0000, language_fan thusly wrote:

 Thu, 24 Sep 2009 15:33:38 -0400, Jarrett Billingsley thusly wrote:
 
 On Thu, Sep 24, 2009 at 2:36 PM, Aenigmatic <procode adam-dott-com.au>
 wrote:
 No further response to any responses to my previous post's responses
 is a both swift and non-invasive.

 Now my deeply thought question is ...

 Is typedef (in D) a C/C++ legacy or is the dear orphan now adopted as
 a first-class citizen in the US of D?

It's a different beast, and in my experience, pretty useless. Most of the time you want typedef'ed types to interact with other types a little more richly. Say you want to use a double as a time. Okay, what do you get when you subtract two points in time? Not a time, that's for sure. You get a time _span_ instead. So you end up implementing them as structs. Virtually every time I've tried to use typedef, it hasn't sufficed and I've ended up using a struct instead. It seems like a failed idea, or at the very least, yet another half-thought-out abandoned feature.

I can imagine some uses for it when the type is very simple, and you fear that the compiler cannot inline operations on structs. Other than that, common mainstream language features like typedefs, variant!(), and enums are mere special cases of algebraic datatypes (with some implicit syntactic sugar). There are some downsides, too, but I prefer to have the more general type in languages that I use.

If I recall correctly, one of the reasons that also make typedefs in D a bit more useless is the inconsistency in implicit casts. E.g. when you create a temperature type, I think some of the conversions between floats, Temperature, and literals fail.
Sep 24 2009
prev sibling next sibling parent Rainer Deyke <rainerd eldwood.com> writes:
Aenigmatic wrote:
 Is typedef (in D) a C/C++ legacy or is the dear orphan now adopted as
 a first-class citizen in the US of D?

typedef in D is a new feature not found in C or C++. The typedef from C/C++ has been renamed to alias and extended to non-types in D. -- Rainer Deyke - rainerd eldwood.com
Sep 24 2009
prev sibling parent reply Chad J <chadjoan __spam.is.bad__gmail.com> writes:
Hmmmm, there's a lot of hating on typedef.

I've found it rather useful for at least one thing:

typedef uint ColorFormat;
enum : ColorFormat
{
	RGB,
	RGBA,
	HSV,
	CMYK,
	// etc
}

Now you have an enum that is type safe but doesn't require a qualified
name to use.

void convertToFormat( SomeTextureType someTexture, ColorFormat fmt )
{
	// etc
}

void main()
{
	// ...
	auto foo = new SomeTextureType(...);

	convertToFormat(foo, 1); // Error, 1 is not a ColorFormat
	convertToFormat(foo, ColorFormat.RGBA ); // Nope*
	convertToFormat(foo, RGBA); // This works.
}

* It is possible to declare named enums that are also typesafe but
require the enum member to be qualified by the enum's name as in this
line.  Such enums are declared like so:

enum ColorFormat : uint
{
// etc
}
Sep 25 2009
next sibling parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
Chad J wrote:
 Hmmmm, there's a lot of hating on typedef.
 
 I've found it rather useful for at least one thing:
 
 typedef uint ColorFormat;
 enum : ColorFormat
 {
 	RGB,
 	RGBA,
 	HSV,
 	CMYK,
 	// etc
 }
 
 Now you have an enum that is type safe but doesn't require a qualified
 name to use.
 
 void convertToFormat( SomeTextureType someTexture, ColorFormat fmt )
 {
 	// etc
 }
 
 void main()
 {
 	// ...
 	auto foo = new SomeTextureType(...);
 
 	convertToFormat(foo, 1); // Error, 1 is not a ColorFormat
 	convertToFormat(foo, ColorFormat.RGBA ); // Nope*
 	convertToFormat(foo, RGBA); // This works.
 }

I should also add that a ColorFormat is implicitly convertable to a uint, so you should be able to use it as an array index to populate tables and such too. As such, typedefs are not completely incompatible with their parent type, but are considered as specialization of the parent type.
Sep 25 2009
prev sibling parent Rainer Deyke <rainerd eldwood.com> writes:
Chad J wrote:
 typedef uint ColorFormat;
 enum : ColorFormat
 {
 	RGB,
 	RGBA,
 	HSV,
 	CMYK,
 	// etc
 }

I always do the opposite in C++: namespace color_formats { enum ColorFormat { RGB, RGBA, HSV, CMYK, // ... }; } using color_formats::ColorFormat; This way I don't pollute my outer namespaces with enum symbols. -- Rainer Deyke - rainerd eldwood.com
Sep 25 2009