www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - typedef alternative

reply "Yao G." <nospamyao gmail.com> writes:
Hello.

Is there an alternative to typedef? I need to define three structs that  
have exactly the same methods and properties, yet represent different  
stuff.

Example:
---
struct Foo
{
     this( int f ) {
         _foo = f;
     }

     int asNumber() {
         return _foo;
     }

     private immutable int _foo;
}

// This should be typedef, but as it's going to be deprecated...
alias Foo Year;
alias Foo Month;
alias Foo Day;


void bar( Year y, Month m, Day d ) {
     // ...
}

// This should compile, obviously.
bar( Year(2010), Month(8), Day(14) );

// But this shouldn't
bar( Day(1), Year(1), Month(1) );
---

So, what options do I have? I know that typedef is scheduled to  
deprecation, so I would like to know if there's something else.


-- 
Yao G.
Aug 14 2010
next sibling parent Jonathan M Davis <jmdavisprog gmail.com> writes:
Okay, I'm not familiar with what typedef is supposed to have done in D. I've 
only ever used alias. But what is wrong with

On Saturday 14 August 2010 17:47:44 Yao G. wrote:
 // This should be typedef, but as it's going to be deprecated...
 alias Foo Year;
 alias Foo Month;
 alias Foo Day;

Is it because Year, Month, Day, and Foo are still completely interchangeable, and you should be able to do things like pass a Year to function that takes a Month? Are you looking to create a new type that while technically identical to another type is not considered the same as that type by the type system? - Jonathan M Davis
Aug 14 2010
prev sibling next sibling parent "Yao G." <nospamyao gmail.com> writes:
On Sat, 14 Aug 2010 20:05:04 -0500, Jonathan M Davis  
<jmdavisprog gmail.com> wrote:

 [snip]

 Are you looking to create a new type that while technically identical to
 another type is not considered the same as that type by the type system?

 - Jonathan M Davis

Yes, This is exactly what I want. I need, for example, that if you pass a Year instance to the Month parameter, generate a compiler error. -- Yao G.
Aug 14 2010
prev sibling next sibling parent sybrandy <sybrandy gmail.com> writes:
I can't recall if you can do this with structs, but if you use classes, 
you should be able to define a "Date Part" class that has all of the 
methods and data you want.  Then, you just derive three sub-classes.

For example (and I hope the syntax is right):

class DatePart
{
    this(int f)
    {
       _foo = f;
    }

    int asNumber() { return _foo; }

    immutable int _foo;
}

class Year: DatePart {}

class Month: DatePart {}

class Day: DatePart {}

Casey

On 08/14/2010 08:47 PM, Yao G. wrote:
 Hello.

 Is there an alternative to typedef? I need to define three structs that
 have exactly the same methods and properties, yet represent different
 stuff.

 Example:
 ---
 struct Foo
 {
 this( int f ) {
 _foo = f;
 }

 int asNumber() {
 return _foo;
 }

 private immutable int _foo;
 }

 // This should be typedef, but as it's going to be deprecated...
 alias Foo Year;
 alias Foo Month;
 alias Foo Day;


 void bar( Year y, Month m, Day d ) {
 // ...
 }

 // This should compile, obviously.
 bar( Year(2010), Month(8), Day(14) );

 // But this shouldn't
 bar( Day(1), Year(1), Month(1) );
 ---

 So, what options do I have? I know that typedef is scheduled to
 deprecation, so I would like to know if there's something else.

Aug 14 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisprog gmail.com> writes:
On Saturday 14 August 2010 18:15:40 Yao G. wrote:
 On Sat, 14 Aug 2010 20:05:04 -0500, Jonathan M Davis
 
 <jmdavisprog gmail.com> wrote:
 [snip]
 
 Are you looking to create a new type that while technically identical to
 another type is not considered the same as that type by the type system?
 
 - Jonathan M Davis

Yes, This is exactly what I want. I need, for example, that if you pass a Year instance to the Month parameter, generate a compiler error.

Well, if you search the D list for typedef, you should find some posts that suggest templated structs combined with alias which get you typedefs. It sounds like something like that will probably end up in Phobos at some point, though apparently there are some issues with conversions (though what they would be if you're trying to keep the types completely separate, I don't know). - Jonathan M Davis
Aug 14 2010
prev sibling next sibling parent "Yao G." <nospamyao gmail.com> writes:
On Sat, 14 Aug 2010 20:28:56 -0500, sybrandy <sybrandy gmail.com> wrote:

 I can't recall if you can do this with structs, but if you use classes,  
 you should be able to define a "Date Part" class that has all of the  
 methods and data you want.  Then, you just derive three sub-classes.

 For example (and I hope the syntax is right):

 class DatePart
 {
     this(int f)
     {
        _foo = f;
     }

     int asNumber() { return _foo; }

     immutable int _foo;
 }

 class Year: DatePart {}

 class Month: DatePart {}

 class Day: DatePart {}

 Casey

Yes. Unfortunately, I need to use structs because the types that I'm defining are value types. But thanks for the answer -- Yao G.
Aug 14 2010
prev sibling next sibling parent "Yao G." <nospamyao gmail.com> writes:
On Sat, 14 Aug 2010 20:34:02 -0500, Jonathan M Davis  
<jmdavisprog gmail.com> wrote:

 Well, if you search the D list for typedef, you should find some posts  
 that
 suggest templated structs combined with alias which get you typedefs. It  
 sounds
 like something like that will probably end up in Phobos at some point,  
 though
 apparently there are some issues with conversions (though what they  
 would be if
 you're trying to keep the types completely separate, I don't know).

 - Jonathan M Davis

Indeed. I did a search on the news group and found this code in a Trass3r post:
 enum Type
 {
      Independent,
      Super,
      Sub,
      Parallel,
 }

 struct Typedef( T, Type type = Type.Sub, T init = T.init, string _f =  
 __FILE__, int _l = __LINE__ )
 {
      T payload = init;

      static if ( type != Type.Independent )
      {
          this( T value )
          {
              payload = value;
          }
      }
      static if ( type == Type.Sub || type == Type.Parallel )
      {
          alias payload this;
      }
      static if ( type == Type.Super )
      {
          typeof( this ) opAssign( T value )
          {
              payload = value;
              return this;
          }
      }
      else static if ( type == Type.Sub )
      {
           disable void opAssign( T value );
      }
 }

I think I'll do something similar as this. I don't need either explicit or implicit cast between types. -- Yao G.
Aug 14 2010
prev sibling parent "Yao G." <nospamyao gmail.com> writes:
I settled this just using an enum value passed as template argument:

---
enum DatePart
{
     Year,
     Month,
     Day,
}

struct DatePartImpl(T : DatePart )
{
     // Insert implementation here...
}

alias DatePartImpl!(DatePart.Year)  Year;
alias DatePartImpl!(DatePart.Month) Month;
alias DatePartImpl!(DatePart.Day)   Day;

void foo( Year y, Month m, Day d ) {}

// Works correctly
foo( Year(2010), Month(8), Day(14) );

// But this isn't allowed
foo( Day(14), Year(2010), Month(8) );
---


-- 
Yao G.
Aug 14 2010