Jump to page: 1 2
Thread overview
Is there a way to remove the requirement for parenthesis?
Jan 21, 2009
Charles Hixson
Jan 21, 2009
Charles Hixson
Jan 21, 2009
Denis Koroskin
Jan 26, 2009
Sergey Gromov
Jan 28, 2009
Charles Hixson
Jan 28, 2009
Daniel Keep
Jan 28, 2009
Charles Hixson
Jan 28, 2009
Denis Koroskin
Jan 28, 2009
Charles Hixson
Jan 29, 2009
Daniel Keep
Jan 29, 2009
Charles Hixson
January 21, 2009
In this test I'm trying to emulate how I want a typedef to act, but I run into a problem:

import   std.stdio;

struct   BlockNum
{  uint   value;

   uint   opCast()   {   return   value;   }
   void   opAssign (uint val)   {   value = val;   }
   uint   opCall()   {   return   value;   }
}

void   main()
{  BlockNum   test;
   test   =   42;
   uint   tst2   =   test();  // <<== if I don't have the parenthesis I
                              //    get a compiler error (cast
                              //    required).
          //  kfile.d(15): Error: cannot implicitly convert expression
          //          (test) of type BlockNum to uint

   writef ("tst2 = %d\n", tst2);
}

It seemed to me as if the parens shouldn't be required here, but I seem mistaken.  Which leads to ugly code.  Is there a way around this?
January 21, 2009
P.S.:  This is Digital Mars D Compiler v2.023 running on Linux

Charles Hixson wrote:
> In this test I'm trying to emulate how I want a typedef to act, but I run into a problem:
> 
> import   std.stdio;
> 
> struct   BlockNum
> {  uint   value;
> 
>    uint   opCast()   {   return   value;   }
>    void   opAssign (uint val)   {   value = val;   }
>    uint   opCall()   {   return   value;   }
> }
> 
> void   main()
> {  BlockNum   test;
>    test   =   42;
>    uint   tst2   =   test();  // <<== if I don't have the parenthesis I
>                               //    get a compiler error (cast
>                               //    required).
>           //  kfile.d(15): Error: cannot implicitly convert expression
>           //          (test) of type BlockNum to uint
> 
>    writef ("tst2 = %d\n", tst2);
> }
> 
> It seemed to me as if the parens shouldn't be required here, but I seem mistaken.  Which leads to ugly code.  Is there a way around this?
January 21, 2009
On Wed, 21 Jan 2009 20:26:08 +0300, Charles Hixson <charleshixsn@earthlink.net> wrote:

> P.S.:  This is Digital Mars D Compiler v2.023 running on Linux
>
> Charles Hixson wrote:
>> In this test I'm trying to emulate how I want a typedef to act, but I run into a problem:
>>  import   std.stdio;
>>  struct   BlockNum
>> {  uint   value;
>>     uint   opCast()   {   return   value;   }
>>    void   opAssign (uint val)   {   value = val;   }
>>    uint   opCall()   {   return   value;   }
>> }
>>  void   main()
>> {  BlockNum   test;
>>    test   =   42;
>>    uint   tst2   =   test();  // <<== if I don't have the parenthesis I
>>                               //    get a compiler error (cast
>>                               //    required).
>>           //  kfile.d(15): Error: cannot implicitly convert expression
>>           //          (test) of type BlockNum to uint
>>     writef ("tst2 = %d\n", tst2);
>> }
>>  It seemed to me as if the parens shouldn't be required here, but I seem mistaken.  Which leads to ugly code.  Is there a way around this?

No, there isn't. It leads to ambiguity and here is why:

class Foo
{
   Foo opCall() { return new Foo(); }
}

void main() {
   Foo bar = new Foo();
   auto ambiguous = bar; // is it 'bar' or 'bar()'?
}

One more case where empty pair of parens is mandatory.

To Walter & Co: Please, oh *PLEASE* drop this feature and give us real properties!

January 26, 2009
Wed, 21 Jan 2009 09:24:01 -0800, Charles Hixson wrote:

> In this test I'm trying to emulate how I want a typedef to act, but I run into a problem:
> 
> import   std.stdio;
> 
> struct   BlockNum
> {  uint   value;
> 
>     uint   opCast()   {   return   value;   }
>     void   opAssign (uint val)   {   value = val;   }
>     uint   opCall()   {   return   value;   }
> }
> 
> void   main()
> {  BlockNum   test;
>     test   =   42;
>     uint   tst2   =   test();  // <<== if I don't have the parenthesis I
>                                //    get a compiler error (cast
>                                //    required).
>            //  kfile.d(15): Error: cannot implicitly convert expression
>            //          (test) of type BlockNum to uint
> 
>     writef ("tst2 = %d\n", tst2);
> }
> 
> It seemed to me as if the parens shouldn't be required here, but I seem mistaken.  Which leads to ugly code.  Is there a way around this?

test is an expression of type BlockNum.  opCall() is called when you use
parentheses syntax on it.  opCast() is called when you use cast() syntax
for it.  Otherwise it stays BlockNum and therefore is not convertible to
uint.
January 28, 2009
Sergey Gromov wrote:
> Wed, 21 Jan 2009 09:24:01 -0800, Charles Hixson wrote:
> 
>> In this test I'm trying to emulate how I want a typedef to act, but I run into a problem:
>>
>> import   std.stdio;
>>
>> struct   BlockNum
>> {  uint   value;
>>
>>     uint   opCast()   {   return   value;   }
>>     void   opAssign (uint val)   {   value = val;   }
>>     uint   opCall()   {   return   value;   }
>> }
>>
>> void   main()
>> {  BlockNum   test;
>>     test   =   42;
>>     uint   tst2   =   test();  // <<== if I don't have the parenthesis I
>>                                //    get a compiler error (cast
>>                                //    required).
>>            //  kfile.d(15): Error: cannot implicitly convert expression
>>            //          (test) of type BlockNum to uint
>>
>>     writef ("tst2 = %d\n", tst2);
>> }
>>
>> It seemed to me as if the parens shouldn't be required here, but I seem mistaken.  Which leads to ugly code.  Is there a way around this?
> 
> test is an expression of type BlockNum.  opCall() is called when you use
> parentheses syntax on it.  opCast() is called when you use cast() syntax
> for it.  Otherwise it stays BlockNum and therefore is not convertible to
> uint.
I think that means "No, there isn't a way around it."
OK.  I'll just ...
well, I'm not totally sure.  Either give up type safety or ... something else.
January 28, 2009
Honestly, I can't see what you're trying to accomplish.  It looks like you want something that's not called int, but which works exactly like an int does, and can be passed as one.

If you just want another name for "int", you can use an alias.

From the compiler's POV, there's no difference between "BlockNum" and "int".

> alias int BlockNum;
> BlockNum a = 42;
> someFuncThatTakesAnInt(a);

If you want to have a type that is an int, but which won't allow itself to directly interact with ints, use a typedef.

Personally, I like this usage for simple numeric values which I don't want to accidentally mix with other types.  Yes, it's a bit of a pain to do arithmetic, but that's the trade-off you make.

From the compiler's POV, "BlockNum" and "int" are totally distinct, incompatible types that just happen to be the same under the hood.

> typedef int BlockNum;
> BlockNum a = cast(BlockNum) 42;
> someFuncThatTakesAnInt(cast(int) a);

The last is if you need something that's basically an int, but you want it to behave differently.  In that case, a struct with operators is your best bet.

Let's say you wanted to do something like a Meters struct to store lengths.  I'd do something like this:

> struct Meters {
>     private int value;
>     int asInt() { return value; }
>     int asInt(int v) { return value=v; }
>     // ... operator overloads ...
> }
>
> Meters a; a.asInt = 42;
> someFuncThatTakesAnInt( a.asInt );

I can't really offer more than that, since I don't know what it is you're trying to accomplish.

  -- Daniel
January 28, 2009
I guess I'm going to do that, but it causes an annoying proliferation of casts throughout the program whenever I need to interact with a library call that recognized more than one int type.  (The compiler, D2.023 on Linux) doesn't seem to properly upcast the type.

Perhaps I'll write separate functions through which to interact with library routines.  Unpleasant and messy, but better than scattering casts all over the code (as long as they get optimized away).

Daniel Keep wrote:
> Honestly, I can't see what you're trying to accomplish.  It looks like
> you want something that's not called int, but which works exactly like
> an int does, and can be passed as one.
> 
> If you just want another name for "int", you can use an alias.
> 
> From the compiler's POV, there's no difference between "BlockNum" and "int".
> 
>> alias int BlockNum;
>> BlockNum a = 42;
>> someFuncThatTakesAnInt(a);
> 
> If you want to have a type that is an int, but which won't allow itself
> to directly interact with ints, use a typedef.
> 
> Personally, I like this usage for simple numeric values which I don't
> want to accidentally mix with other types.  Yes, it's a bit of a pain to
> do arithmetic, but that's the trade-off you make.
> 
> From the compiler's POV, "BlockNum" and "int" are totally distinct,
> incompatible types that just happen to be the same under the hood.
> 
>> typedef int BlockNum;
>> BlockNum a = cast(BlockNum) 42;
>> someFuncThatTakesAnInt(cast(int) a);
> 
> The last is if you need something that's basically an int, but you want
> it to behave differently.  In that case, a struct with operators is your
> best bet.
> 
> Let's say you wanted to do something like a Meters struct to store
> lengths.  I'd do something like this:
> 
>> struct Meters {
>>     private int value;
>>     int asInt() { return value; }
>>     int asInt(int v) { return value=v; }
>>     // ... operator overloads ...
>> }
>>
>> Meters a; a.asInt = 42;
>> someFuncThatTakesAnInt( a.asInt );
> 
> I can't really offer more than that, since I don't know what it is
> you're trying to accomplish.
> 
>   -- Daniel
January 28, 2009
On Wed, 28 Jan 2009 08:45:12 +0300, Daniel Keep <daniel.keep.lists@gmail.com> wrote:

>
> Honestly, I can't see what you're trying to accomplish.  It looks like
> you want something that's not called int, but which works exactly like
> an int does, and can be passed as one.
>
> If you just want another name for "int", you can use an alias.
>
> From the compiler's POV, there's no difference between "BlockNum" and "int".
>
>> alias int BlockNum;
>> BlockNum a = 42;
>> someFuncThatTakesAnInt(a);
>
> If you want to have a type that is an int, but which won't allow itself
> to directly interact with ints, use a typedef.
>
> Personally, I like this usage for simple numeric values which I don't
> want to accidentally mix with other types.  Yes, it's a bit of a pain to
> do arithmetic, but that's the trade-off you make.
>
> From the compiler's POV, "BlockNum" and "int" are totally distinct,
> incompatible types that just happen to be the same under the hood.
>
>> typedef int BlockNum;
>> BlockNum a = cast(BlockNum) 42;
>> someFuncThatTakesAnInt(cast(int) a);
>
> The last is if you need something that's basically an int, but you want
> it to behave differently.  In that case, a struct with operators is your
> best bet.
>
> Let's say you wanted to do something like a Meters struct to store
> lengths.  I'd do something like this:
>
>> struct Meters {
>>     private int value;
>>     int asInt() { return value; }
>>     int asInt(int v) { return value=v; }
>>     // ... operator overloads ...
>> }
>>
>> Meters a; a.asInt = 42;
>> someFuncThatTakesAnInt( a.asInt );
>
> I can't really offer more than that, since I don't know what it is
> you're trying to accomplish.
>
>   -- Daniel

Perhaps, he wants opImplicitCast?

January 28, 2009
Suppose that you have four types, equivalent to, say, float.
Call one of them Horiz, one Vertic, one Radians, and one Radius.
These are all floats, but when you specify, say,
float dist (Horiz x, Vert y)
{  return sqrt(x * x + y * y);  }
It's important that the arguments aren't Radius and Radians.  Or Horiz and Horiz.

Denis Koroskin wrote:
> On Wed, 28 Jan 2009 08:45:12 +0300, Daniel Keep <daniel.keep.lists@gmail.com> wrote:
> 
>>
>> Honestly, I can't see what you're trying to accomplish.  It looks like
>> you want something that's not called int, but which works exactly like
>> an int does, and can be passed as one.
>>
>> If you just want another name for "int", you can use an alias.
>>
>> From the compiler's POV, there's no difference between "BlockNum" and "int".
>>
>>> alias int BlockNum;
>>> BlockNum a = 42;
>>> someFuncThatTakesAnInt(a);
>>
>> If you want to have a type that is an int, but which won't allow itself
>> to directly interact with ints, use a typedef.
>>
>> Personally, I like this usage for simple numeric values which I don't
>> want to accidentally mix with other types.  Yes, it's a bit of a pain to
>> do arithmetic, but that's the trade-off you make.
>>
>> From the compiler's POV, "BlockNum" and "int" are totally distinct,
>> incompatible types that just happen to be the same under the hood.
>>
>>> typedef int BlockNum;
>>> BlockNum a = cast(BlockNum) 42;
>>> someFuncThatTakesAnInt(cast(int) a);
>>
>> The last is if you need something that's basically an int, but you want
>> it to behave differently.  In that case, a struct with operators is your
>> best bet.
>>
>> Let's say you wanted to do something like a Meters struct to store
>> lengths.  I'd do something like this:
>>
>>> struct Meters {
>>>     private int value;
>>>     int asInt() { return value; }
>>>     int asInt(int v) { return value=v; }
>>>     // ... operator overloads ...
>>> }
>>>
>>> Meters a; a.asInt = 42;
>>> someFuncThatTakesAnInt( a.asInt );
>>
>> I can't really offer more than that, since I don't know what it is
>> you're trying to accomplish.
>>
>>   -- Daniel
> 
> Perhaps, he wants opImplicitCast?
> 
January 29, 2009

Charles Hixson wrote:
> Suppose that you have four types, equivalent to, say, float.
> Call one of them Horiz, one Vertic, one Radians, and one Radius.
> These are all floats, but when you specify, say,
> float dist (Horiz x, Vert y)
> {  return sqrt(x * x + y * y);  }
> It's important that the arguments aren't Radius and Radians.  Or Horiz
> and Horiz.
> 
> [snip]

There's no problem with that: make them structs that implement the appropriate operators.

See, what I don't get (note: this is how I perceive it) is the desire to
have this sort of type protection, but require the compiler to somehow
be psychic in order to know when and where you don't care and throw it away.

You either have distinct types that aren't automatically compatible, or you don't.

  -- Daniel
« First   ‹ Prev
1 2