Bug 12597 – Payload getter for std.typecons.Typedef

Status
NEW
Severity
enhancement
Priority
P4
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-04-19T10:23:08Z
Last change time
2024-12-01T16:20:50Z
Assigned to
No Owner
Creator
bearophile_hugs
Moved to GitHub: phobos#10047 →

Comments

Comment #0 by bearophile_hugs — 2014-04-19T10:23:08Z
Currently if you want to call a function sin/cos on a Typedef (here used to define a strongly typed angle), you need a cast: void main() { import std.typecons: Typedef; import std.math: sin; alias Angle = Typedef!double; Angle x = 0.5; auto y1 = sin(x); // Error. auto y2 = sin(cast(double)x); // OK. } So to avoid the unsafe cast I suggest to add a getter to Typedef: auto y3 = sin(x.get);
Comment #1 by andrej.mitrovich — 2014-04-19T10:35:32Z
Looks fairly innocent, but what if the original type is a user-defined type that already defines the get() method?
Comment #2 by bearophile_hugs — 2014-04-19T12:21:15Z
(In reply to Andrej Mitrovic from comment #1) > what if the original type is a user-defined type > that already defines the get() method? Then perhaps you need to write this? auto y3 = sin(x.get.get);
Comment #3 by andrej.mitrovich — 2014-04-19T12:23:32Z
(In reply to bearophile_hugs from comment #2) > (In reply to Andrej Mitrovic from comment #1) > > > what if the original type is a user-defined type > > that already defines the get() method? > > Then perhaps you need to write this? > > auto y3 = sin(x.get.get); That would cause existing and generic code to break. For example: ----- module test; import std.typecons; struct S { int get() { return 0; } } alias S2 = Typedef!S; void main() { S2 s2; auto x = s2.get(); // works now } ----- If we want a solid Typedef in D2 then we have to take this into account as well.
Comment #4 by bearophile_hugs — 2014-04-19T12:47:30Z
(In reply to Andrej Mitrovic from comment #3) > That would cause existing and generic code to break. I see. On the other hand currently Typedef has several problems, and all or almost all bug reports/ERs on it are mine, so I doubt there is a lot of existing code that uses it :-)
Comment #5 by andrej.mitrovich — 2014-04-19T12:50:49Z
(In reply to bearophile_hugs from comment #4) > (In reply to Andrej Mitrovic from comment #3) > > > That would cause existing and generic code to break. > > I see. On the other hand currently Typedef has several problems, and all or > almost all bug reports/ERs on it are mine, so I doubt there is a lot of > existing code that uses it :-) Yeah I know. But there are plenty of people on IRC that keep asking about it though, I typically don't recommend them to use Typedef since it's full of bugs.
Comment #6 by andrej.mitrovich — 2014-04-22T21:21:52Z
You seem to have filed https://issues.dlang.org/show_bug.cgi?id=11706 before, maybe we should just implement that instead? Then the cast would be safe.
Comment #7 by bearophile_hugs — 2014-04-22T21:38:43Z
(In reply to Andrej Mitrovic from comment #5) > there are plenty of people on IRC that keep asking about it > though, I typically don't recommend them to use Typedef since it's full of > bugs. While not strictly necessary, something like typedef/Typedef is sometimes useful. In Haskell there's a built-in way to do it, using "newtype", and the GHC compiler has one or more non-standard extensions (GeneralizedNewtypeDeriving) to improve the use of newtype. (In reply to Andrej Mitrovic from comment #6) > You seem to have filed https://issues.dlang.org/show_bug.cgi?id=11706 > before, maybe we should just implement that instead? Then the cast would be > safe. The need to find the underlying type and the underlying value are both present. So I think we need both enhancements. (I have also just added a note to Issue 11706 ). If you want to implement only one of the two, then I suggest to implement a way to get the underlying value, because then getting the type is one typedef away.
Comment #8 by bearophile_hugs — 2014-04-22T21:40:07Z
(In reply to bearophile_hugs from comment #7) >because then getting the type is one typedef away. Sorry, I meant to write one typeof away.
Comment #9 by andrej.mitrovich — 2014-04-24T10:58:47Z
Would this getter give ref access? If so, we might as well make the `Typedef_payload` field public. Otherwise we could make a UFCS function that would avoid symbol conflicts: ----- V getValue(T)(T t) /* if (isTypedef!T) */ { return t.Typedef_payload; } ----- This would be usable via: Typedef!Type x; x.getValue(); // assuming 'Type' doesn't define getValue getValue(x); // workaround if 'Type' *does* define getValue Let me know what you think.
Comment #10 by bearophile_hugs — 2014-04-24T11:21:07Z
(In reply to Andrej Mitrovic from comment #9) > we might as well make the `Typedef_payload` field public. Yes, making that field public could be the simplest solution. But the field needs to be renamed to a nicer/shorter name, perhaps like "_data". > Otherwise we could make a UFCS function that > would avoid symbol conflicts: > > ----- > V getValue(T)(T t) > /* if (isTypedef!T) */ > { > return t.Typedef_payload; > } > ----- > > This would be usable via: > > Typedef!Type x; > x.getValue(); // assuming 'Type' doesn't define getValue > getValue(x); // workaround if 'Type' *does* define getValue > > Let me know what you think. Seems good, but to reduce the frequency of name clashes I'd like a less generic/common name, like "typedefVal". And if possible it should return by reference: Typedef!Int x; x.typedefVal++;
Comment #11 by monkeyworks12 — 2014-09-24T21:26:33Z
I think this enhancement request should be closed now that https://github.com/D-Programming-Language/phobos/pull/2116 has been merged. With that PR, your first example now becomes: void main() { import std.typecons: Typedef; import std.math: sin; alias Angle = Typedef!double; Angle x = 0.5; auto y1 = sin(x); // Error. auto y2 = sin(cast(TypedefType!Angle)x); // OK. } A bit verbose, but it accomplishes what you want and is more DRY and safer than cast(double)x.
Comment #12 by bearophile_hugs — 2014-09-25T21:09:19Z
(In reply to monkeyworks12 from comment #11) > I think this enhancement request should be closed now that > https://github.com/D-Programming-Language/phobos/pull/2116 has been merged. > With that PR, your first example now becomes: > > void main() { > import std.typecons: Typedef; > import std.math: sin; > alias Angle = Typedef!double; > Angle x = 0.5; > auto y1 = sin(x); // Error. > auto y2 = sin(cast(TypedefType!Angle)x); // OK. > } > > A bit verbose, but it accomplishes what you want and is more DRY and safer > than cast(double)x. This ER asks for a function like "typedefVal" that's usable like: auto y2 = x.typedefVal.sin; // OK. Casts are unsafe, their usage should be minimized in D code. So this ER is still valid.
Comment #13 by monkeyworks12 — 2014-09-26T04:24:56Z
(In reply to bearophile_hugs from comment #12) > (In reply to monkeyworks12 from comment #11) > > I think this enhancement request should be closed now that > > https://github.com/D-Programming-Language/phobos/pull/2116 has been merged. > > With that PR, your first example now becomes: > > > > void main() { > > import std.typecons: Typedef; > > import std.math: sin; > > alias Angle = Typedef!double; > > Angle x = 0.5; > > auto y1 = sin(x); // Error. > > auto y2 = sin(cast(TypedefType!Angle)x); // OK. > > } > > > > A bit verbose, but it accomplishes what you want and is more DRY and safer > > than cast(double)x. > > This ER asks for a function like "typedefVal" that's usable like: > > auto y2 = x.typedefVal.sin; // OK. > > Casts are unsafe, their usage should be minimized in D code. So this ER is > still valid. But casting to TypedefType!(typeof(x)) is always safe, so if you want such a function, it's trivial to add one yourself. The main problem (getting the underlying type of a Typedef) is solved. auto typedefVal(T)(T val) { return cast(TypedefType!T)val; }
Comment #14 by bearophile_hugs — 2014-09-26T08:50:22Z
(In reply to monkeyworks12 from comment #13) > But casting to TypedefType!(typeof(x)) is always safe, If it's always safe it shouldn't look dangerous, so it it shouldn't look like "cast(" in a textual search. > so if you want such a function, it's trivial to add one yourself. > The main problem (getting the underlying type of a Typedef) is solved. > > auto typedefVal(T)(T val) > { > return cast(TypedefType!T)val; > } Yes, this ER asks for such safe function in Phobos.
Comment #15 by bearophile_hugs — 2014-09-26T10:07:25Z
(In reply to bearophile_hugs from comment #14) > > auto typedefVal(T)(T val) > > { > > return cast(TypedefType!T)val; > > } > > Yes, this ER asks for such safe function in Phobos. But it's better to add a template constraint to that T to be sure it's a Typedef.
Comment #16 by Bastiaan — 2018-03-13T12:40:33Z
(In reply to bearophile_hugs from comment #15) > (In reply to bearophile_hugs from comment #14) > > > > auto typedefVal(T)(T val) > > > { > > > return cast(TypedefType!T)val; > > > } > > > > Yes, this ER asks for such safe function in Phobos. > > But it's better to add a template constraint to that T to be sure it's a > Typedef. No need: /// Instantiating with a non-Typedef will return that type static assert(is(TypedefType!int == int));
Comment #17 by josipp — 2022-04-03T19:13:39Z
(In reply to bearophile_hugs from comment #14) > (In reply to monkeyworks12 from comment #13) > > > But casting to TypedefType!(typeof(x)) is always safe, > > If it's always safe it shouldn't look dangerous, so it it shouldn't look > like "cast(" in a textual search. > > > > so if you want such a function, it's trivial to add one yourself. > > The main problem (getting the underlying type of a Typedef) is solved. > > > > auto typedefVal(T)(T val) > > { > > return cast(TypedefType!T)val; > > } > > Yes, this ER asks for such safe function in Phobos. Could this be integrated into the definition of `std.conv.to(T)`? The module `std.conv` is described as a one-stop-shop for converting different types into each other, after all. I see a very clear objective here to safely and explicitly cast the underlying value to its corresponding type, and the `to` template is very well-suited for that kind of transformation.
Comment #18 by robert.schadek — 2024-12-01T16:20:50Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/phobos/issues/10047 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB