digitalmars.D.learn - Is there a way to remove the requirement for parenthesis?
- Charles Hixson (21/21) Jan 21 2009 In this test I'm trying to emulate how I want a typedef to act, but I
- Charles Hixson (2/29) Jan 21 2009
- Denis Koroskin (12/35) Jan 21 2009 No, there isn't. It leads to ambiguity and here is why:
- Sergey Gromov (5/32) Jan 25 2009 test is an expression of type BlockNum. opCall() is called when you use
- Charles Hixson (5/39) Jan 27 2009 I think that means "No, there isn't a way around it."
- Daniel Keep (20/34) Jan 27 2009 Honestly, I can't see what you're trying to accomplish. It looks like
- Charles Hixson (8/55) Jan 27 2009 I guess I'm going to do that, but it causes an annoying proliferation of...
- Denis Koroskin (2/38) Jan 28 2009 Perhaps, he wants opImplicitCast?
- Charles Hixson (8/63) Jan 28 2009 Suppose that you have four types, equivalent to, say, float.
- Daniel Keep (9/18) Jan 28 2009 There's no problem with that: make them structs that implement the
- Charles Hixson (14/37) Jan 28 2009 No such requirement. If it's based on a type, then it can be used as
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?
Jan 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?
Jan 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: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!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?
Jan 21 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.
Jan 25 2009
Sergey Gromov wrote:Wed, 21 Jan 2009 09:24:01 -0800, Charles Hixson wrote: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.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.
Jan 27 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
Jan 27 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
Jan 27 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".Perhaps, he wants opImplicitCast?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
Jan 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".Perhaps, he wants opImplicitCast?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
Jan 28 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
Jan 28 2009
Daniel Keep wrote:Charles Hixson wrote:No such requirement. If it's based on a type, then it can be used as that type. But the converse shouldn't be true. I.e., in the example it should require extra effort to use a float where a Horiz was requested. (Cast would reasonably be required here.) But to use a Horiz as a float should be trivial. Actually, typedef almost works for this. The problem is that if, e.g., one defines typedef uint MyType; and then does writef (MyType); the compiler asks whether I mean to use a byte or a ulong. It doesn't automatically realize that the appropriate type is uint. (Again, this is D2.023 on Linux.)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
Jan 28 2009