digitalmars.D.learn - using a typedefed variable with library classes
- Charles Hixson (14/14) Jan 10 2009 Is it possible to use a typedefed variable with library classes?
- Bill Baxter (9/23) Jan 10 2009 I've never found a use for typedef myself. I don't think it's used
- Charles Hixson (2/33) Jan 10 2009 Sorry. Yes, it was D2. Guess I'll just avoid it then. (Pity.)
- bearophile (15/16) Jan 10 2009 In Pascal (and its variant and children, like ObjectPascals, etc) there ...
- Bill Baxter (33/47) Jan 10 2009 ,<
- bearophile (6/12) Jan 11 2009 You are right, typedef was invented before classes and OOP, so what you ...
- Charles Hixson (14/32) Jan 11 2009 Well, my use case just involves being able to use library function with
- Sergey Gromov (28/43) Jan 12 2009 Well, I presume File.write() has many overloads, including one for int
- Bill Baxter (8/14) Jan 12 2009 But the difference is LocalType can be converted to int exactly in all
- Sergey Gromov (7/23) Jan 12 2009 It's about overload resolution rules. The specs say:
- Charles Hixson (4/56) Jan 14 2009 A) Yes, it works the way that you say. This damages it's utility.
- Christopher Wright (6/9) Jan 15 2009 The point of a typedef is to provide additional type safety. This would
- Charles Hixson (10/20) Jan 17 2009 That's all that's needed to solve the use case that I presented.
- Christopher Wright (19/24) Jan 18 2009 The following works for me (using LDC):
- Christopher Wright (14/16) Jan 18 2009 Actually, you said you had two methods, something like this:
- Christopher Wright (3/5) Jan 18 2009 Okay, you can compile with warnings and dmd yells at you. But that's
Is it possible to use a typedefed variable with library classes? In particular, what I've done is: typedef int TestType; TestType t; File f; t = 42; f.write (t); And the response I get is the compiler asking whether I want to write bytes or a long. Am I doing something grossly wrong? Or is typedef just broken? Or is it really supposed to work that way for some not-understood reason? (alias works fine...but this seems to make typedef basically useless. Unless there's a way of adding functions to the library classes [like file] so that they'll understand how to cast the typedefed variable.)
Jan 10 2009
On Sun, Jan 11, 2009 at 8:23 AM, Charles Hixson <charleshixsn earthlink.net> wrote:Is it possible to use a typedefed variable with library classes? In particular, what I've done is: typedef int TestType; TestType t; File f; t = 42; f.write (t); And the response I get is the compiler asking whether I want to write bytes or a long. Am I doing something grossly wrong? Or is typedef just broken? Or is it really supposed to work that way for some not-understood reason? (alias works fine...but this seems to make typedef basically useless. Unless there's a way of adding functions to the library classes [like file] so that they'll understand how to cast the typedefed variable.)I've never found a use for typedef myself. I don't think it's used much, so it could be that it's a special case that Andrei didn't consider when re-writing write() [at least I'm assuming you're talking D2, based on the error message]. Or it could be that it is a bug with the compiler. But either way I think no one uses it, so it's likely to flush out lots of corner cases. --bb
Jan 10 2009
Bill Baxter wrote:On Sun, Jan 11, 2009 at 8:23 AM, Charles Hixson <charleshixsn earthlink.net> wrote:Sorry. Yes, it was D2. Guess I'll just avoid it then. (Pity.)Is it possible to use a typedefed variable with library classes? In particular, what I've done is: typedef int TestType; TestType t; File f; t = 42; f.write (t); And the response I get is the compiler asking whether I want to write bytes or a long. Am I doing something grossly wrong? Or is typedef just broken? Or is it really supposed to work that way for some not-understood reason? (alias works fine...but this seems to make typedef basically useless. Unless there's a way of adding functions to the library classes [like file] so that they'll understand how to cast the typedefed variable.)I've never found a use for typedef myself. I don't think it's used much, so it could be that it's a special case that Andrei didn't consider when re-writing write() [at least I'm assuming you're talking D2, based on the error message]. Or it could be that it is a bug with the compiler. But either way I think no one uses it, so it's likely to flush out lots of corner cases. --bb
Jan 10 2009
Bill Baxter:I've never found a use for typedef myself. I don't think it's used much,<In Pascal (and its variant and children, like ObjectPascals, etc) there is a section named Type where you define your typedefs. People used to program in Pascal-like languages (ObjectPascals, Ada, Oberon, etc) may appreciate the typedef of D and they may use it. I use typedef now and then, I presume it's mostly useful for imperative style of programming and not much in OOP. A simple usage example: you have a procedural/functional program that has several functions that process a matrix, the same matrix, for example a float[12][7]. In such situation you may want to define: typedef float[12][7] FPfield; Then if you use FPField in function signatures like this: void foo(FPfield mat, ...) { ... } you gain some things: - The type name may be shorter, saving you some typing. And you don't need to remember each time the size of the dimensions. - If you later want to FPfield into a matrix of doubles or the matrix you have to change only one line. If your code uses a dynamic array this is less important. But from coding a lot of programs in D I have seen programs up to 2-5-10 times faster when I use 3D/4D static arrays, mostly because lot of address computations are done at compile time or partially optimized away instead of run time, and because of higher cache coherence. I can show an extreme example, if you want. D dynamic arrays can't replace all static arrays where speed matters. - It's a way to document the code, because you aren't just giving a generic matrix to foo, you are giving it a FPfield, this often has an important semantic meaning. - It's type safe, so you don't risk giving the wrong matrix to foo. You can't do this well with an alias. This is more useful in largish programs. If you use OOP or lot generic programming this becomes less important. Bye, bearophile
Jan 10 2009
On Sun, Jan 11, 2009 at 10:16 AM, bearophile <bearophileHUGS lycos.com> wro= te:Bill Baxter:,<I've never found a use for typedef myself. I don't think it's used much=In Pascal (and its variant and children, like ObjectPascals, etc) there i=s a section named Type where you define your typedefs. People used to progr= am in Pascal-like languages (ObjectPascals, Ada, Oberon, etc) may appreciat= e the typedef of D and they may use it.I use typedef now and then, I presume it's mostly useful for imperative s=tyle of programming and not much in OOP.A simple usage example: you have a procedural/functional program that has=several functions that process a matrix, the same matrix, for example a fl= oat[12][7]. In such situation you may want to define:typedef float[12][7] FPfield; Then if you use FPField in function signatures like this: void foo(FPfield mat, ...) { ... } you gain some things: - The type name may be shorter, saving you some typing. And you don't nee=d to remember each time the size of the dimensions.- If you later want to FPfield into a matrix of doubles or the matrix you=have to change only one line. If your code uses a dynamic array this is le= ss important. But from coding a lot of programs in D I have seen programs u= p to 2-5-10 times faster when I use 3D/4D static arrays, mostly because lot= of address computations are done at compile time or partially optimized aw= ay instead of run time, and because of higher cache coherence. I can show a= n extreme example, if you want. D dynamic arrays can't replace all static a= rrays where speed matters.- It's a way to document the code, because you aren't just giving a gener=ic matrix to foo, you are giving it a FPfield, this often has an important = semantic meaning.- It's type safe, so you don't risk giving the wrong matrix to foo. You c=an't do this well with an alias. This is more useful in largish programs.If you use OOP or lot generic programming this becomes less important.Actually it might be useful to me. The first time I tried to use it my thought was to do typedef Exception MyException; To create a different exception type. That doesn't work so I kinda just said, eh whatever, this typedef stuff doesn't work yet. But probably that's just because that's not the use case they were intended= for. Something I might be able to use it for is for index types. Like this: typedef size_t VertexHandle; typedef size_t FaceHandle; Now I can't accidentally assign a vertex handle to a face handle. That could be useful. --bb
Jan 10 2009
Bill Baxter:The first time I tried to use it my thought was to do typedef Exception MyException; To create a different exception type. That doesn't work so I kinda just said, eh whatever, this typedef stuff doesn't work yet.You are right, typedef was invented before classes and OOP, so what you say doesn't work :-) But I think typedef may be modified to work as you want too, that is to define a subtype (so the runtime typeinfo of MyException too has to be different!). I/we can ask Walter what he thinks about this.Now I can't accidentally assign a vertex handle to a face handle. That could be useful.Right. But so far I don't see problems in extending the semantics of typedef to work with OOP too. Maybe other people here can spot a problem. I presume Walter doesn't read this newsgroup, so I can post a summary in the main D group too, later. Bye, bearophile
Jan 11 2009
bearophile wrote:Bill Baxter:Well, my use case just involves being able to use library function with the proper base type. (I.e., int instead of long or byte when I do typedef int LocalType; LocalType t; File f; f.write(t); I'll grant that I *can* use alias for such a purpose, but that doesn't distinguish between LocalType and ArrayIndex in routines defined for those types. E.g.: typedef int ArrayIndex; void zeroIndex(out ArrayIndex ai) { ai = 0; } zeroIndex(t); Should throw an error. If I'm using alias it doesn't (and shouldn't);The first time I tried to use it my thought was to do typedef Exception MyException; To create a different exception type. That doesn't work so I kinda just said, eh whatever, this typedef stuff doesn't work yet.You are right, typedef was invented before classes and OOP, so what you say doesn't work :-) But I think typedef may be modified to work as you want too, that is to define a subtype (so the runtime typeinfo of MyException too has to be different!). I/we can ask Walter what he thinks about this.Now I can't accidentally assign a vertex handle to a face handle. That could be useful.Right. But so far I don't see problems in extending the semantics of typedef to work with OOP too. Maybe other people here can spot a problem. I presume Walter doesn't read this newsgroup, so I can post a summary in the main D group too, later. Bye, bearophile
Jan 11 2009
Sun, 11 Jan 2009 18:09:15 -0800, Charles Hixson wrote:Well, my use case just involves being able to use library function with the proper base type. (I.e., int instead of long or byte when I do typedef int LocalType; LocalType t; File f; f.write(t); I'll grant that I *can* use alias for such a purpose, but that doesn't distinguish between LocalType and ArrayIndex in routines defined for those types. E.g.: typedef int ArrayIndex; void zeroIndex(out ArrayIndex ai) { ai = 0; } zeroIndex(t); Should throw an error. If I'm using alias it doesn't (and shouldn't);Well, I presume File.write() has many overloads, including one for int but none for LocalType. When aliasing, the LocalType *is* an int, it matches exactly File.write(int) and the compiler is happy. However, with a typedef, LocalType is a distinct type. Yes it casts to int implicitly, but likewise it casts implicitly to char, short and long. So compiler gets a whole load of File.write() functions matching with conversions, and fails because of the ambiguity. That's how the language works, and it's pretty consistent IMO. What you can do is: f.write(cast(int)t); or use templates to generalize: auto fileWrite(T : LocalType)(File f, T v) { return f.write(cast(int)v); } auto fileWrite(T)(File f, T v) { return f.write(v); } fileWrite(f, t); // OK fileWrite(f, 15); // OK When we get generic function calls you'd be even able to write: void write(File f, LocalType l) { f.write(cast(int)l); } f.write(t); // OK, write(f, t) is called
Jan 12 2009
On Tue, Jan 13, 2009 at 1:48 AM, Sergey Gromov <snake.scaly gmail.com> wrote:However, with a typedef, LocalType is a distinct type. Yes it casts to int implicitly, but likewise it casts implicitly to char, short and long. So compiler gets a whole load of File.write() functions matching with conversions, and fails because of the ambiguity. That's how the language works, and it's pretty consistent IMO. What you can do is:But the difference is LocalType can be converted to int exactly in all cases. Given a choice of int,char,short,etc. clearly the conversion to int is best choice. It may be consistent with other cases involving multiple legal conversions, but usually you don't have such a single clearly preferred conversion. It seems to significantly reduce the utility of typedef. --bb
Jan 12 2009
Tue, 13 Jan 2009 05:59:58 +0900, Bill Baxter wrote:On Tue, Jan 13, 2009 at 1:48 AM, Sergey Gromov <snake.scaly gmail.com> wrote:It's about overload resolution rules. The specs say: The levels of matching are: * no match * match with implicit conversions * exact match There is no notion of 'best' implicit conversion.However, with a typedef, LocalType is a distinct type. Yes it casts to int implicitly, but likewise it casts implicitly to char, short and long. So compiler gets a whole load of File.write() functions matching with conversions, and fails because of the ambiguity. That's how the language works, and it's pretty consistent IMO. What you can do is:But the difference is LocalType can be converted to int exactly in all cases. Given a choice of int,char,short,etc. clearly the conversion to int is best choice. It may be consistent with other cases involving multiple legal conversions, but usually you don't have such a single clearly preferred conversion. It seems to significantly reduce the utility of typedef.
Jan 12 2009
Sergey Gromov wrote:Sun, 11 Jan 2009 18:09:15 -0800, Charles Hixson wrote:A) Yes, it works the way that you say. This damages it's utility. B) I'm replying to a question as to how typedef could reasonably be extended.Well, my use case just involves being able to use library function with the proper base type. (I.e., int instead of long or byte when I do typedef int LocalType; LocalType t; File f; f.write(t); I'll grant that I *can* use alias for such a purpose, but that doesn't distinguish between LocalType and ArrayIndex in routines defined for those types. E.g.: typedef int ArrayIndex; void zeroIndex(out ArrayIndex ai) { ai = 0; } zeroIndex(t); Should throw an error. If I'm using alias it doesn't (and shouldn't);Well, I presume File.write() has many overloads, including one for int but none for LocalType. When aliasing, the LocalType *is* an int, it matches exactly File.write(int) and the compiler is happy. However, with a typedef, LocalType is a distinct type. Yes it casts to int implicitly, but likewise it casts implicitly to char, short and long. So compiler gets a whole load of File.write() functions matching with conversions, and fails because of the ambiguity. That's how the language works, and it's pretty consistent IMO. What you can do is: f.write(cast(int)t); or use templates to generalize: auto fileWrite(T : LocalType)(File f, T v) { return f.write(cast(int)v); } auto fileWrite(T)(File f, T v) { return f.write(v); } fileWrite(f, t); // OK fileWrite(f, 15); // OK When we get generic function calls you'd be even able to write: void write(File f, LocalType l) { f.write(cast(int)l); } f.write(t); // OK, write(f, t) is called
Jan 14 2009
Charles Hixson wrote:A) Yes, it works the way that you say. This damages it's utility. B) I'm replying to a question as to how typedef could reasonably be extended.The point of a typedef is to provide additional type safety. This would not exist if you could implicitly cast back and forth. Unless you want an implicit cast from a typedef type to the base type, and not the reverse -- that might be reasonable (I can't immediately see any issues with it).
Jan 15 2009
Christopher Wright wrote:Charles Hixson wrote:That's all that's needed to solve the use case that I presented. Unfortunately, what it tried to do was cast it to either byte or long rather than the base case (which was int). Fortunately it couldn't decide which to cast it as, as either choice would have been an error. (I'm writing to a binary file, and the size of the item written is significant.) Because of this, to avoid scattering casts throughout the program, I had to replace the typedef with alias. This works, but it also definitely prevents the type safety that a typedef could (should) have provided.A) Yes, it works the way that you say. This damages it's utility. B) I'm replying to a question as to how typedef could reasonably be extended.The point of a typedef is to provide additional type safety. This would not exist if you could implicitly cast back and forth. Unless you want an implicit cast from a typedef type to the base type, and not the reverse -- that might be reasonable (I can't immediately see any issues with it).
Jan 17 2009
Charles Hixson wrote:Unfortunately, what it tried to do was cast it to either byte or long rather than the base case (which was int). Fortunately it couldn't decide which to cast it as, as either choice would have been an error. (I'm writing to a binary file, and the size of the item written is significant.)The following works for me (using LDC): typedef int mint; void foo (long i) {} void main () { mint a = 1; foo (a); } However, this also works: typedef int mint; void foo (byte i) {} void main () { mint a = 1; foo (a); } It's an implicit narrowing conversion -- that involves data loss. This is a bug.
Jan 18 2009
Christopher Wright wrote:It's an implicit narrowing conversion -- that involves data loss. This is a bug.Actually, you said you had two methods, something like this: void foo (byte i) {} void foo (long i) {} void main () { int a = 1; foo (a); byte b = a; // no casts } This example doesn't use typedefs but still complains about overloads. I find it odd that you can implicitly cast an arithmetic type of one width to another of a smaller width. I'm making a feature enhancement request for this.
Jan 18 2009
Christopher Wright wrote:It's an implicit narrowing conversion -- that involves data loss. This is a bug.Okay, you can compile with warnings and dmd yells at you. But that's about it. This is pretty cruddy.
Jan 18 2009