www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Inferred Type for Explicit Cast

reply "Jonathan Marler" <johnnymarler gmail.com> writes:
What are peoples thoughts on having an inferred type for "cast"? 
Good/Bad idea? If good, how helpful would this be? Would this 
break existing code somehow? I think this feature would be a nice 
added convenience.  Not super helpful but nice to have.

Here's the details
-------------------
Typed Cast: cast(T)v
   try to cast v to T
Type Inferred Cast: cast(auto)v
   try to cast v to whatever type is required in the current 
context

void foo(string s)
{
   // ...
}
void main()
{
     const(char)[] s = "hello";
     foo(cast(string)s); // Current
     foo(cast(auto) s);  // The type of the cast is inferred to be 
a string
     foo(cast() s);      // Another possible syntax
}

This would help refactoribility.  If a function argument changes 
it's type, and the caller is using a cast, then the caller's cast 
type will be updated automatically.  Note that if it changes to 
an invalid type, the cast will still fail like normal.
Dec 18 2014
next sibling parent reply ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thu, 18 Dec 2014 22:46:04 +0000
Jonathan Marler via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 What are peoples thoughts on having an inferred type for "cast"?=20
 Good/Bad idea? If good, how helpful would this be? Would this=20
 break existing code somehow? I think this feature would be a nice=20
 added convenience.  Not super helpful but nice to have.
=20
 Here's the details
 -------------------
 Typed Cast: cast(T)v
    try to cast v to T
 Type Inferred Cast: cast(auto)v
    try to cast v to whatever type is required in the current=20
 context
=20
 void foo(string s)
 {
    // ...
 }
 void main()
 {
      const(char)[] s =3D "hello";
      foo(cast(string)s); // Current
      foo(cast(auto) s);  // The type of the cast is inferred to be=20
 a string
      foo(cast() s);      // Another possible syntax
 }
=20
 This would help refactoribility.  If a function argument changes=20
 it's type, and the caller is using a cast, then the caller's cast=20
 type will be updated automatically.  Note that if it changes to=20
 an invalid type, the cast will still fail like normal.
using casts is a bad practice. and "auto casts" is... i can't even find a word. the only thing this will help is to hide bugs, i believe. please, don't. nothing personal, i'm just terrified by the idea.
Dec 18 2014
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 18 December 2014 at 23:06:12 UTC, ketmar via 
Digitalmars-d wrote:
 the only thing this will help is to hide bugs, i believe.
On the contrary, I find explicit casts hide bugs. Suppose you write: size_t a = cast(int) b; It will compile and run. It'll mostly work. But the cast to int probably wasn't intended (it was probably written in 32 bit code and not correctly ported to 64 bit). How often do we also write auto a = cast(T) b;? The difference would be the type is written on the left side instead of the right. Might make an important differnce when calling functions. I think the auto cast is a win all around.
Dec 18 2014
next sibling parent ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thu, 18 Dec 2014 23:18:16 +0000
"Adam D. Ruppe via Digitalmars-d" <digitalmars-d puremagic.com> wrote:

 On Thursday, 18 December 2014 at 23:06:12 UTC, ketmar via=20
 Digitalmars-d wrote:
 the only thing this will help is to hide bugs, i believe.
=20 On the contrary, I find explicit casts hide bugs. Suppose you=20 write: =20 size_t a =3D cast(int) b; =20 It will compile and run. It'll mostly work. But the cast to int=20 probably wasn't intended (it was probably written in 32 bit code=20 and not correctly ported to 64 bit). =20 How often do we also write auto a =3D cast(T) b;? The difference=20 would be the type is written on the left side instead of the=20 right. Might make an important differnce when calling functions. =20 I think the auto cast is a win all around.
explicit cast are immediately decipherable (except of `cast(typeof(result))` maybe). i.e. `cast(int)` is surely casts to `int`. but what is `cast(auto)`? to what type it will cast the value? this makes the language unnecessary puzzling, and will not save from bugs anyway. `size_t a =3D cast(int)b;`? so `b` must be long/ulong, and the author guarantees that b will never be bigger than `int.max`. perfect. in no way `cast(auto)` will save us from the bug here: it will simply hide the author intentions.
Dec 18 2014
prev sibling next sibling parent ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thu, 18 Dec 2014 23:18:16 +0000
"Adam D. Ruppe via Digitalmars-d" <digitalmars-d puremagic.com> wrote:

 On Thursday, 18 December 2014 at 23:06:12 UTC, ketmar via=20
 Digitalmars-d wrote:
 the only thing this will help is to hide bugs, i believe.
=20 On the contrary, I find explicit casts hide bugs. Suppose you=20 write: =20 size_t a =3D cast(int) b; =20 It will compile and run. It'll mostly work. But the cast to int=20 probably wasn't intended (it was probably written in 32 bit code=20 and not correctly ported to 64 bit). =20 How often do we also write auto a =3D cast(T) b;? The difference=20 would be the type is written on the left side instead of the=20 right. Might make an important differnce when calling functions. =20 I think the auto cast is a win all around.
p.s. with functions it's even more puzzling: now i have to look at the function signature to deduce the actual type. if such calls are rare, there is no need for "auto casts". if such calls are frequent, write a wrapper function or template!
Dec 18 2014
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/18/14 6:18 PM, Adam D. Ruppe wrote:
 On Thursday, 18 December 2014 at 23:06:12 UTC, ketmar via Digitalmars-d
 wrote:
 the only thing this will help is to hide bugs, i believe.
On the contrary, I find explicit casts hide bugs. Suppose you write: size_t a = cast(int) b; It will compile and run. It'll mostly work. But the cast to int probably wasn't intended (it was probably written in 32 bit code and not correctly ported to 64 bit). How often do we also write auto a = cast(T) b;? The difference would be the type is written on the left side instead of the right. Might make an important differnce when calling functions. I think the auto cast is a win all around.
I have to agree with ketmar. Cast needs fixing, but this is not it. We need more control over what is cast, not less control. Your example unwittingly shows the issue :) casts are blunt instruments that force the compiler to abandon it's checks. I'm not as concerned about a changing it's type as I am about b. Change the type of b, and the compiler still happily generates possibly disastrous code. At this point, we can only say "abandon ALL checks." We can't finely tune this. I think we need something more along the lines of C++'s casting directives. And in answer to your above code snippet, I see no benefit for: size_t a = cast(auto) b; over: auto a = cast(size_t) b; -Steve
Dec 19 2014
next sibling parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
On Friday, 19 December 2014 at 15:17:04 UTC, Steven Schveighoffer 
wrote:
 On 12/18/14 6:18 PM, Adam D. Ruppe wrote:
 On Thursday, 18 December 2014 at 23:06:12 UTC, ketmar via 
 Digitalmars-d
 wrote:
 the only thing this will help is to hide bugs, i believe.
On the contrary, I find explicit casts hide bugs. Suppose you write: size_t a = cast(int) b; It will compile and run. It'll mostly work. But the cast to int probably wasn't intended (it was probably written in 32 bit code and not correctly ported to 64 bit). How often do we also write auto a = cast(T) b;? The difference would be the type is written on the left side instead of the right. Might make an important differnce when calling functions. I think the auto cast is a win all around.
I have to agree with ketmar. Cast needs fixing, but this is not it. We need more control over what is cast, not less control. Your example unwittingly shows the issue :) casts are blunt instruments that force the compiler to abandon it's checks. I'm not as concerned about a changing it's type as I am about b. Change the type of b, and the compiler still happily generates possibly disastrous code. At this point, we can only say "abandon ALL checks." We can't finely tune this. I think we need something more along the lines of C++'s casting directives. And in answer to your above code snippet, I see no benefit for: size_t a = cast(auto) b; over: auto a = cast(size_t) b; -Steve
Nobody likes to use cast, but for now we are stuck with it. Creating alternatives to cast would be a great thing to discuss but doesn't really apply to the point at hand, which is, would cast(auto) be a useful extension to our current cast operator? I think it could be. In my opinion, if we allow return value types to be written as "auto" then it makes since to have cast(auto) as well. In both cases the developer would need to look somewhere else to find what type "auto" actually gets resolved to. The way I look at it, cast(auto) is like saying, "hey compiler, I know this value can't be implicitly converted so just pretend like I've given you an explicit cast to whatever type you need". Note that this cast is still under the constraints of an explicit cast. You can't cast a struct to an int or whatever. I can't really think of a case where this would be more dangerous than a typed explicit cast but I didn't think too long:)
Dec 20 2014
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Jonathan Marler:

 if we allow return value types to be written as "auto" then it 
 makes since to have cast(auto) as well.
I think "cast(auto)" as I understand in your proposal introduces too often undefined situations, because in many cases the compiler can't know what's the type to cast to, and guessing is not acceptable. So I think it's not a good idea. But sometimes I have code like this: void main() { int x; byte y; // ... y = cast(typeof(y))x; } Here I want to cast x to the type of y to allow the assignment to y. This is perhaps an acceptable semantics for "cast(auto)": void main() { int x; byte y; // ... y = cast(auto)x; // OK } In that case the inference for the casting type is easy because the type of y is already defined. More examples: void foo(byte z) {} void main() { int x; // ... auto y = cast(auto)x; // Error byte y = cast(auto)x; // OK, but not very useful foo(cast(auto)x); // OK } Bye, bearophile
Dec 20 2014
parent "Jonathan Marler" <johnnymarler gmail.com> writes:
On Saturday, 20 December 2014 at 10:14:10 UTC, bearophile wrote:
 Jonathan Marler:

 if we allow return value types to be written as "auto" then it 
 makes since to have cast(auto) as well.
I think "cast(auto)" as I understand in your proposal introduces too often undefined situations, because in many cases the compiler can't know what's the type to cast to, and guessing is not acceptable. So I think it's not a good idea.
You gave one example of an 'undefined situation' (auto y = cast(auto)x). However this situation is clearly an error (not undefined). I think what you meant was that the type of auto is undefined, not the situation itself. To this you are correct. I fail to see why that makes this a bad idea. The whole concept of 'auto' is not defined in many situations but that doesn't make it a bad idea. If you were a programmer and you declared a variable y using auto, why would you think you need to cast it? int x; auto y = x; // Normal auto y = cast(int)x; // huh? there's not reason to do this The only reason I could think of is when you want to explicitly say what type y should be. But why would you do that using a cast? Just declare y as the type you want to be and skip 'auto'. byte y = cast(byte)x; Ah but now you have to keep the type of y and the cast "in sync". So you could write this; auto y = cast(byte)x; It looks a little weird but it works. I however think that if you want y to be a specific type, you should declare it as such (instead of using auto). byte y = cast(byte)x; We're back to the previous example. However now we are faced with the same problem of keeping the 2 types in sync. You could use cast(typeof(y)) to solve this, or you could use cast(auto). byte y = cast(typeof(y))x; byte y = cast(auto)x; cast(auto) looks nicer but both work fine. The problem with cast(typeof(y)) is that it doesn't work when you are assigning x to an unnamed variable (like a function argument).
 But sometimes I have code like this:

 void main() {
     int x;
     byte y;
     // ...
     y = cast(typeof(y))x;
 }


 Here I want to cast x to the type of y to allow the assignment 
 to y. This is perhaps an acceptable semantics for "cast(auto)":


 void main() {
     int x;
     byte y;
     // ...
     y = cast(auto)x; // OK
 }


 In that case the inference for the casting type is easy because 
 the type of y is already defined. More examples:


 void foo(byte z) {}
 void main() {
     int x;
     // ...
     auto y = cast(auto)x; // Error
     byte y = cast(auto)x; // OK, but not very useful
     foo(cast(auto)x);     // OK
 }

 Bye,
 bearophile-
Lastly I would like to say that cast(auto) provides a bit of functionality that is currently nowhere in the language. It's not the same as cast(typeof(var)) since that cast needs a named variable to refer to. It would provide some functionality for templates that are currently nowhere in the langauge. I haven't thought of an example yet but if you think of one let me know:)
Dec 20 2014
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/20/14 3:36 AM, Jonathan Marler wrote:

 Nobody likes to use cast, but for now we are stuck with it. Creating
 alternatives to cast would be a great thing to discuss but doesn't
 really apply to the point at hand, which is, would cast(auto) be a
 useful extension to our current cast operator?  I think it could be.  In
 my opinion, if we allow return value types to be written as "auto" then
 it makes since to have cast(auto) as well.  In both cases the developer
 would need to look somewhere else to find what type "auto" actually gets
 resolved to.
You have to be careful here, when you think about who is in charge of what. For an auto return, it is the function author who is deciding what auto should resolve to. But cast(auto) is letting the author of the called function dictate. This is a decoupling of who is responsible for the type vs. who is requesting the cast. Now, just 'auto' is fine, because you are not subverting the type system, and unsafe behavior cannot result. But with something like 'cast', you are potentially playing with fire. For instance, let's say you have a function which accepts an int, but the author changes it later to accept a pointer to an int. You are passing in a size_t, via cast(auto), now the compiler happily reinterprets the size_t as a pointer, and you are in dangerous territory. You can think of it this way. With cast(T), you are saying "I've examined the possibilities of casting this value to type T, I know what I'm doing". With cast(auto) you are saying "I'm OK with this value casting to any other value that cast may work with. I know what I'm doing." I find that the requirement of just typing "cast(auto)" does not match the gravity of the analysis that is required to ensure that is true. -Steve
Dec 20 2014
parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
On Sunday, 21 December 2014 at 03:04:05 UTC, Steven Schveighoffer 
wrote:
 On 12/20/14 3:36 AM, Jonathan Marler wrote:

 Nobody likes to use cast, but for now we are stuck with it. 
 Creating
 alternatives to cast would be a great thing to discuss but 
 doesn't
 really apply to the point at hand, which is, would cast(auto) 
 be a
 useful extension to our current cast operator?  I think it 
 could be.  In
 my opinion, if we allow return value types to be written as 
 "auto" then
 it makes since to have cast(auto) as well.  In both cases the 
 developer
 would need to look somewhere else to find what type "auto" 
 actually gets
 resolved to.
You have to be careful here, when you think about who is in charge of what. For an auto return, it is the function author who is deciding what auto should resolve to. But cast(auto) is letting the author of the called function dictate. This is a decoupling of who is responsible for the type vs. who is requesting the cast. Now, just 'auto' is fine, because you are not subverting the type system, and unsafe behavior cannot result. But with something like 'cast', you are potentially playing with fire. For instance, let's say you have a function which accepts an int, but the author changes it later to accept a pointer to an int. You are passing in a size_t, via cast(auto), now the compiler happily reinterprets the size_t as a pointer, and you are in dangerous territory. You can think of it this way. With cast(T), you are saying "I've examined the possibilities of casting this value to type T, I know what I'm doing". With cast(auto) you are saying "I'm OK with this value casting to any other value that cast may work with. I know what I'm doing." I find that the requirement of just typing "cast(auto)" does not match the gravity of the analysis that is required to ensure that is true. -Steve
That is a case I hadn't initially thought of. I definitely don't like that. As for the typed cast, what about when the function argument is changed from a byte to a short? If the initial caller was using cast(byte) and doesn't change to cast(short), then you are also creating a bug. I feel like you're going to get different bugs either way. Both the typed and auto-typed cast seem to be just as dangerous. That's not really an argument to have auto-cast, I'm just making an observation. I noticed your other comment about wanting a double-typed cast. I could see that being useful especially if we did something like this: When a cast is performed, the source and target type must match the expected types EXACTLY. int y; ushort x = cast(byte, int)y; // cast from int to byte This should definitely produce an error. This code could exist if x was initially a byte and was later changed to a ushort. I think this feature would make casts alot safer because any time a type was changed you would get an error saying you need to go update all your casts. What do you think?
Dec 21 2014
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/21/14 3:23 AM, Jonathan Marler wrote:

 As for the typed cast, what about when the function argument is changed
 from a byte to a short?  If the initial caller was using cast(byte) and
 doesn't change to cast(short), then you are also creating a bug.  I feel
 like you're going to get different bugs either way.  Both the typed and
 auto-typed cast seem to be just as dangerous.  That's not really an
 argument to have auto-cast, I'm just making an observation.
But as the author, you have examined your code, and determined it's OK to have whatever expression you are using cast to a byte. This means you are sure it won't exceed the byte range. I don't see how this is a bug.
 I noticed your other comment about wanting a double-typed cast. I could
 see that being useful especially if we did something like this:

    When a cast is performed, the source and target type must match the
 expected types EXACTLY.

 int y;
 ushort x = cast(byte, int)y; // cast from int to byte

 This should definitely produce an error.  This code could exist if x was
 initially a byte and was later changed to a ushort. I think this feature
 would make casts alot safer because any time a type was changed you
 would get an error saying you need to go update all your casts. What do
 you think?
I didn't think of it that way, I would assume that cast(byte, int) would only error if the cast-from type is not int, not if the expression used the result in any way other than a byte. But it does have appeal. -Steve
Dec 21 2014
parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
 I noticed your other comment about wanting a double-typed 
 cast. I could
 see that being useful especially if we did something like this:

   When a cast is performed, the source and target type must 
 match the
 expected types EXACTLY.

 int y;
 ushort x = cast(byte, int)y; // cast from int to byte

 This should definitely produce an error.  This code could 
 exist if x was
 initially a byte and was later changed to a ushort. I think 
 this feature
 would make casts alot safer because any time a type was 
 changed you
 would get an error saying you need to go update all your 
 casts. What do
 you think?
I didn't think of it that way, I would assume that cast(byte, int) would only error if the cast-from type is not int, not if the expression used the result in any way other than a byte. But it does have appeal. -Steve
It seems alot of the potential bugs from casting can occur when one of the types change. If we forced the cast operator to match the type(s) exactly then it would eliminate all these bugs.
Dec 21 2014
next sibling parent ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sun, 21 Dec 2014 15:20:44 +0000
Jonathan Marler via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 It seems alot of the potential bugs from casting can occur when=20
 one of the types change.  If we forced the cast operator to match=20
 the type(s) exactly then it would eliminate all these bugs.
that is what i mean by "don't use hacks"! what many people think about when there is need to convert from one type to another? CAST IT! not "convert it", but "cast it". but we have idiomatic "to!" for type conversion. still puzzled a little? ;-) i'm about "hide that cast in system module in faraway land" again. int z; short a; z.castassignto!(short)(a); // OK z.castassignto!(byte)(a); // FAIL this is ugly? yes, exactly as it should be. this is working? yes. we can use it to enforce both types too: castassignto!(int, short)(z, a); will this work? oops, nope... as we have no control on argument type deduction for templates, one can write: z.castassignto!(a); ahem... is this `cast(auto)`? ;-) ok, to make a long story short: the idea is to replace explicit casts by templated casts. templates gives us more control, can have more arguments and if we'll do a ER that allows us to control argument type deduction will give us way to control what must be specified and what can be omited.
Dec 21 2014
prev sibling parent ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sun, 21 Dec 2014 15:20:44 +0000
Jonathan Marler via Digitalmars-d <digitalmars-d puremagic.com> wrote:

  `z.castassignto(a);`, of course. ;-)
Dec 21 2014
prev sibling parent "eles" <eles eles.com> writes:
On Sunday, 21 December 2014 at 08:23:58 UTC, Jonathan Marler 
wrote:
 On Sunday, 21 December 2014 at 03:04:05 UTC, Steven 
 Schveighoffer wrote:
 On 12/20/14 3:36 AM, Jonathan Marler wrote:
 int y;
 ushort x = cast(byte, int)y; // cast from int to byte

 This should definitely produce an error.  This code could exist 
 if x was initially a byte and was later changed to a ushort. I 
 think this feature would make casts alot safer because any time 
 a type was changed you would get an error saying you need to go 
 update all your casts. What do you think?
This kinda helps for the other idea that I was mentioning: dissociate the data format/size of the access type when casting. I still find very ugly, in C++, to specify a type to cast to for const_cast. It exposes the same problem, when one type change, you remain with an invalid cast. In C is the same, and even worse. You have to specify that the cast is performed to remove "const"-ness, for example, in *the comments*. If the type change, you have an invalid cast, but the compiler will swallow it happily. Should have "access_cast". That will only throw away const and let the type format/size unchanged. Implicit casting (or another explicit cast) will have to play the game to ensure type compatibility, not the remaining (kinda of) reinterpret_cast.
Dec 29 2014
prev sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Friday, 19 December 2014 at 15:17:04 UTC, Steven Schveighoffer 
wrote:
 On 12/18/14 6:18 PM, Adam D. Ruppe wrote:
 On Thursday, 18 December 2014 at 23:06:12 UTC, ketmar via 
 Digitalmars-d
 wrote:
 the only thing this will help is to hide bugs, i believe.
On the contrary, I find explicit casts hide bugs. Suppose you write: size_t a = cast(int) b; It will compile and run. It'll mostly work. But the cast to int probably wasn't intended (it was probably written in 32 bit code and not correctly ported to 64 bit). How often do we also write auto a = cast(T) b;? The difference would be the type is written on the left side instead of the right. Might make an important differnce when calling functions. I think the auto cast is a win all around.
I have to agree with ketmar. Cast needs fixing, but this is not it. We need more control over what is cast, not less control. Your example unwittingly shows the issue :) casts are blunt instruments that force the compiler to abandon it's checks. I'm not as concerned about a changing it's type as I am about b. Change the type of b, and the compiler still happily generates possibly disastrous code. At this point, we can only say "abandon ALL checks." We can't finely tune this.
I'd like to have a cast where you must define both "from" and "to" types precisely.
Dec 20 2014
next sibling parent "Dicebot" <public dicebot.lv> writes:
It can be added trivially added to Phobos, of course, if more
people consider it useful.
Dec 20 2014
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/20/14 5:20 AM, Dicebot wrote:

 I'd like to have a cast where you must define both "from" and "to" types
 precisely.
I was actually thinking the same thing. This would be almost future-proof (any changes to either side would result in failed compilation). -Steve
Dec 20 2014
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/20/14 6:47 PM, Steven Schveighoffer wrote:
 On 12/20/14 5:20 AM, Dicebot wrote:

 I'd like to have a cast where you must define both "from" and "to" types
 precisely.
I was actually thinking the same thing. This would be almost future-proof (any changes to either side would result in failed compilation). -Steve
Specifying two types instead of one in a "to" call should achieve that. -- Andrei
Dec 23 2014
parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 24 December 2014 at 03:11:40 UTC, Andrei 
Alexandrescu wrote:
 On 12/20/14 6:47 PM, Steven Schveighoffer wrote:
 On 12/20/14 5:20 AM, Dicebot wrote:

 I'd like to have a cast where you must define both "from" and 
 "to" types
 precisely.
I was actually thinking the same thing. This would be almost future-proof (any changes to either side would result in failed compilation). -Steve
Specifying two types instead of one in a "to" call should achieve that. -- Andrei
This is different. `to` is about "smart" conversion (and potentially costly with allocations flying around) - we are speaking about same basic dumb cast here, just more controlled.
Dec 29 2014
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/29/14 6:08 AM, Dicebot wrote:
 On Wednesday, 24 December 2014 at 03:11:40 UTC, Andrei Alexandrescu wrote:
 On 12/20/14 6:47 PM, Steven Schveighoffer wrote:
 On 12/20/14 5:20 AM, Dicebot wrote:

 I'd like to have a cast where you must define both "from" and "to"
 types
 precisely.
I was actually thinking the same thing. This would be almost future-proof (any changes to either side would result in failed compilation). -Steve
Specifying two types instead of one in a "to" call should achieve that. -- Andrei
This is different. `to` is about "smart" conversion (and potentially costly with allocations flying around) - we are speaking about same basic dumb cast here, just more controlled.
I see. I guess it's easy to add std.conv.explicitCast and std.conv.implicitCast if there's enough impetus for it. -- Andrei
Dec 29 2014
parent reply "Dicebot" <public dicebot.lv> writes:
On Monday, 29 December 2014 at 15:50:15 UTC, Andrei Alexandrescu 
wrote:
 I see. I guess it's easy to add std.conv.explicitCast and 
 std.conv.implicitCast if there's enough impetus for it. -- 
 Andrei
Yes, exactly. That was why I have asked general opinion about it - don't want to add yet another utility no one uses. I will probably go and just add it anyway : https://github.com/D-Programming-Language/phobos/pull/2822
Dec 29 2014
parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
On Monday, 29 December 2014 at 16:45:31 UTC, Dicebot wrote:
 On Monday, 29 December 2014 at 15:50:15 UTC, Andrei 
 Alexandrescu wrote:
 I see. I guess it's easy to add std.conv.explicitCast and 
 std.conv.implicitCast if there's enough impetus for it. -- 
 Andrei
Yes, exactly. That was why I have asked general opinion about it - don't want to add yet another utility no one uses. I will probably go and just add it anyway : https://github.com/D-Programming-Language/phobos/pull/2822
+1
Dec 29 2014
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/29/14 10:14 AM, Jonathan Marler wrote:
 On Monday, 29 December 2014 at 16:45:31 UTC, Dicebot wrote:
 On Monday, 29 December 2014 at 15:50:15 UTC, Andrei Alexandrescu wrote:
 I see. I guess it's easy to add std.conv.explicitCast and
 std.conv.implicitCast if there's enough impetus for it. -- Andrei
Yes, exactly. That was why I have asked general opinion about it - don't want to add yet another utility no one uses. I will probably go and just add it anyway : https://github.com/D-Programming-Language/phobos/pull/2822
+1
If you like it, please review it. It took me all of 30 seconds to find a typo. Thanks. -- Andrei
Dec 29 2014
prev sibling parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
On Thursday, 18 December 2014 at 23:06:12 UTC, ketmar via 
Digitalmars-d wrote:
 On Thu, 18 Dec 2014 22:46:04 +0000
 Jonathan Marler via Digitalmars-d <digitalmars-d puremagic.com> 
 wrote:

 What are peoples thoughts on having an inferred type for 
 "cast"? Good/Bad idea? If good, how helpful would this be? 
 Would this break existing code somehow? I think this feature 
 would be a nice added convenience.  Not super helpful but nice 
 to have.
 
 Here's the details
 -------------------
 Typed Cast: cast(T)v
    try to cast v to T
 Type Inferred Cast: cast(auto)v
    try to cast v to whatever type is required in the current 
 context
 
 void foo(string s)
 {
    // ...
 }
 void main()
 {
      const(char)[] s = "hello";
      foo(cast(string)s); // Current
      foo(cast(auto) s);  // The type of the cast is inferred 
 to be a string
      foo(cast() s);      // Another possible syntax
 }
 
 This would help refactoribility.  If a function argument 
 changes it's type, and the caller is using a cast, then the 
 caller's cast type will be updated automatically.  Note that 
 if it changes to an invalid type, the cast will still fail 
 like normal.
using casts is a bad practice. and "auto casts" is... i can't even find a word. the only thing this will help is to hide bugs, i believe. please, don't. nothing personal, i'm just terrified by the idea.
Performing a grep on phobos reveals there are currently almost 3,000 casts. I never like to use casts but they are a necessary evil. I think anything D can do to help the programmer get their job done is a win. The initial "pro" I saw for this idea was improving refactoribility. I see this as a huge win. You claim it will hide bugs? Could you give an example? When I requested other people to chime in on this idea I was more looking for data/examples. Maybe someone will think of an example that shows this idea could encourage bad coding practices? Maybe it will hide bugs? My point is, I don't want to discourage you from providing your opinion, but I would really like to understand where your opinion comes from. I hope that wasn't harsh, I've read other posts you've made on the forums and although I don't agree with everything you say I would value your assessment. Thanks.
Dec 20 2014
parent reply ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sat, 20 Dec 2014 08:18:22 +0000
Jonathan Marler via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 Performing a grep on phobos reveals there are currently almost=20
 3,000 casts.  I never like to use casts but they are a necessary=20
 evil.  I think anything D can do to help the programmer get their=20
 job done is a win.  The initial "pro" I saw for this idea was=20
 improving refactoribility.  I see this as a huge win.  You claim=20
 it will hide bugs?  Could you give an example?
autocasting to the types of function arguments is the immediate weak point. what you doing by this is destroying type checking. ok, we doing that from time to time, but you proposing handy sytax for it which will not break when function signature changes. there is topic about "kind of programmers" nearby, where we found that "majority of programmers don't read books". and they tend to use the first tool they see to "make the job done", don't trying to evaluate the long-term consequences. i can assure you that you'll see `cast(auto)` all over their code, 'cause it's simply, it doesn't require even looking at function signature and trying to grasp why it accepts the given types, and "ah, it's so refactorable!" (they love "refactoring", 'cause they don't like to design their software, plus "refactoring" is often the blessed way to do nothing really valuable and still got payed). besides, `cast` is a hack by itself. the good way to deal with hacks is to make them less powerful, not more powerful. you are proposing to make the hack more powerful. there is nothing bad in it... when the language is designed for use by hardcore hackers. but for languages with greater audience this is not a good way to go. hacks will inevitably be abused. it doesn't matter how many times we write in big letters: "PLEASE, DON'T DO THAT!" so hacks must be small and fine-grained, not small and powerful. besides, `cast(auto)` is not decipherable without analyzing the expression (and, possibly, function signature). it is not clear what result of `cast(auto)` will be. this is bad for hack. why `cast` is hack? 'cause it turns off most of the compiler type checking system. that's why we have `to!XXX` thing, which is not so disasterous. and compiler is smart enough to see that `a&0xff` is good for ubyte, for example. we can't make `cast` less powerful now, but what we surely shouldn't do is making it more poweful.
 When I requested other people to chime in on this idea I was more=20
 looking for data/examples.  Maybe someone will think of an=20
 example that shows this idea could encourage bad coding=20
 practices?  Maybe it will hide bugs?  My point is, I don't want=20
 to discourage you from providing your opinion, but I  would=20
 really like to understand where your opinion comes from. I hope=20
 that wasn't harsh, I've read other posts you've made on the=20
 forums and although I don't agree with everything you say I would=20
 value your assessment. Thanks.
it comes from my past expirience. sometimes i just *sense* the smell. powerful hacks are great troublemakers. making Cassandra prophecies is my superpower. ;-)
Dec 20 2014
parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
On Saturday, 20 December 2014 at 12:36:50 UTC, ketmar via 
Digitalmars-d wrote:
 On Sat, 20 Dec 2014 08:18:22 +0000
 Jonathan Marler via Digitalmars-d <digitalmars-d puremagic.com> 
 wrote:

 Performing a grep on phobos reveals there are currently almost 
 3,000 casts.  I never like to use casts but they are a 
 necessary evil.  I think anything D can do to help the 
 programmer get their job done is a win.  The initial "pro" I 
 saw for this idea was improving refactoribility.  I see this 
 as a huge win.  You claim it will hide bugs?  Could you give 
 an example?
autocasting to the types of function arguments is the immediate weak point.
I see this as one of it's strong points. It provides greater refactoribility, and also has the potential for using casts inside templates to unnamed variables (like function arguments).
 ..what you doing by this is destroying type checking. ok, we 
 doing
 that from time to time, but you proposing handy sytax for it 
 which will
 not break when function signature changes.
casting is not destroying the type checking. You can't convert a value to any type (an int to a struct), it still has to be possible. struct MyStruct{...} int x; MyStruct s; x = cast(int)s; // doesn't work x = cast(auto)s; // still doesn't work
 there is topic about "kind of programmers" nearby, where we 
 found that
 "majority of programmers don't read books". and they tend to 
 use the
 first tool they see to "make the job done", don't trying to 
 evaluate
 the long-term consequences. i can assure you that you'll see
 `cast(auto)` all over their code, 'cause it's simply, it doesn't
 require even looking at function signature and trying to grasp 
 why it
 accepts the given types, and "ah, it's so refactorable!" (they 
 love
 "refactoring", 'cause they don't like to design their software, 
 plus
 "refactoring" is often the blessed way to do nothing really 
 valuable
 and still got payed).
I'm not sure you'll get too many good programmers who agree with you that refactoring is only caused by "lack of design". I'm not sure where to start when trying to list all the reasons someone would want to refactor. New library, better design patter is realized, new feature has come in, new person has come in with a better solution, new api is introduced somewhere...so many reasons. Programmer's aren't perfect, if we did everything right the first time then we never would have had c++ :) D itself is just a refactor. To address your other concern about seeing "cast(auto)" all over someone's code. I think you might start seeing cast(auto) in place of some cast(T), but why would you start seeing cast(auto) in other places? Nobody writes cast when it's unnecessary: int x; int y = cast(int)x; Why would anyone do this? Don't tell me it's because the programmer is too stupid to know what a cast means, you could make that same argument for any feature. Some languages have used that argument to remove any number of unsafe features like pointer arithmetic, non-garbage collected memory, etc. The purpose of D is not to restrict the programmer so they can't make any mistakes, it's purpose is to make programming easier and of course safer but not at the expense of removing the ability to do the unsafe operations when needed. It is true that 'cast' reduces type checking, but it doesn't remove it and it's also necessary.
 besides, `cast` is a hack by itself. the good way to deal with 
 hacks is
 to make them less powerful, not more powerful. you are 
 proposing to
 make the hack more powerful. there is nothing bad in it... when 
 the
 language is designed for use by hardcore hackers. but for 
 languages
 with greater audience this is not a good way to go. hacks will
 inevitably be abused. it doesn't matter how many times we write 
 in big
 letters: "PLEASE, DON'T DO THAT!" so hacks must be small and
 fine-grained, not small and powerful.
cast is not a hack, it's a necessary feature that is well defined. It reduces type safety, which may be why you are calling it a "hack", but unfortunately it is necessary. cast(auto) is a natural extension to a necessary feature that's not going to go away. Type safety is not a simple problem. The more type safe you get the more restrictive your language gets, which causes more need for casting. The less type safe your language is, the less casting you need but then the more unsafe your whole program becomes. D often chooses to make 90% of code safe and provides ways for you to escape the safety of the language for the extra 10%. Cast falls into the category of the 10%. If you go through some examples I think you'll find that cast(auto) used in the cases where it makes sense actually produces code that results in less bugs. But like any tool, of course it can be misused, but that's not a reason to not have it.
 besides, `cast(auto)` is not decipherable without analyzing the
 expression (and, possibly, function signature). it is not clear 
 what
 result of `cast(auto)` will be. this is bad for hack.
Normal auto declarations and using auto as a return type has the same problem. But sometimes you don't care what the type is. If you always needed to know what type something is then templates wouldn't exist.
 why `cast` is hack? 'cause it turns off most of the compiler 
 type
 checking system. that's why we have `to!XXX` thing, which is 
 not so
 disasterous. and compiler is smart enough to see that `a&0xff` 
 is good
 for ubyte, for example.
Again, it doesn't "turn off" type checking, it makes types checking more lenient which is sometimes necessary.
 we can't make `cast` less powerful now, but what we surely 
 shouldn't do
 is making it more poweful.
You're right we can't make it less powerful because it's necessary. If you have an idea on how D could get rid of it we would all love to hear it:)
 When I requested other people to chime in on this idea I was 
 more looking for data/examples.  Maybe someone will think of 
 an example that shows this idea could encourage bad coding 
 practices?  Maybe it will hide bugs?  My point is, I don't 
 want to discourage you from providing your opinion, but I  
 would really like to understand where your opinion comes from. 
 I hope that wasn't harsh, I've read other posts you've made on 
 the forums and although I don't agree with everything you say 
 I would value your assessment. Thanks.
it comes from my past expirience. sometimes i just *sense* the smell. powerful hacks are great troublemakers. making Cassandra prophecies is my superpower. ;-)
Dec 20 2014
parent reply ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sat, 20 Dec 2014 18:19:21 +0000
Jonathan Marler via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 we can't make `cast` less powerful now, but what we surely=20
 shouldn't do
 is making it more poweful.
=20 You're right we can't make it less powerful because it's=20 necessary. If you have an idea on how D could get rid of it we=20 would all love to hear it:)
something like modula's "system" module: if you need `cast`, or pointers, or other "low-level" things, you should import "system" module. and you HAVE to write `system.cast(...)`. make it cumbersome! let `to!XXX` do the work, with all it's checks. making unsafe features easier to use is a way to spread their usage, and i see it as a "generally bad thing".
Dec 20 2014
parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
On Saturday, 20 December 2014 at 19:00:57 UTC, ketmar via 
Digitalmars-d wrote:
 On Sat, 20 Dec 2014 18:19:21 +0000
 Jonathan Marler via Digitalmars-d <digitalmars-d puremagic.com> 
 wrote:

 we can't make `cast` less powerful now, but what we surely 
 shouldn't do
 is making it more poweful.
You're right we can't make it less powerful because it's necessary. If you have an idea on how D could get rid of it we would all love to hear it:)
something like modula's "system" module: if you need `cast`, or pointers, or other "low-level" things, you should import "system" module. and you HAVE to write `system.cast(...)`. make it cumbersome! let `to!XXX` do the work, with all it's checks. making unsafe features easier to use is a way to spread their usage, and i see it as a "generally bad thing".
Hmmmm...an interesting concept. Make unsafe things harder to do to discourage their use. I'm not sure if I agree but maybe you can convince me. Where do you draw the line? If you wanted to make these features harder to use why not make the user type the word cast in a different language like Japanese? Or why not take cast out all together and force the developer to use assembly or another language? You said you could make the user import an unsafe module, why not go a step further and have them type in a password, or have them write out a long specific sequence to perform the cast: byte x = cast$%*% * (*#&&!(($)$ ) $( ($) $$* ( **(!(byte) y; I don't agree that making things harder to use is a good idea, but I do agree that making things more verbose can be a good idea to prevent misuse. It makes sense because in order to use cast you should know what it means and if you know what it means you should know the verbose syntax to use it. That concept makes sense. But in my opinion, the "cast" keyword is enough. It provides a way to audit your code by grepping for the "cast" keyword, and any programmer that sees the word cast and doesn't understand it will likely look up what it means. I could get on board with adding a restriction that you tell the compiler somehow that you are going to use casts in your file (like importing the "system" module), but when you go to use it, I don't think it should be "harder" to use. cast(auto) may be easier to use but it also makes more sense in some cases. I've listed some of the cases in my other posts but the general idea is it requires less maintenance. Say you have the following: void myfunc(uint x) { ubyte val; // // ... // val = cast(ubyte)x; } Now let's say that you need change the value of 'val' to ushort. void myfunc(uint x) { ushort val; // // ... // val = cast(ubyte)x; } Now we have a bug that could be incredibly difficult to find and will likely not be found through typical unit testing. It will probably result in weird unexpected runtime crashes as the invalid cast error propogates through the program until something throws an exception. The error is caused by having to write the same thing in 2 different places. You have to write the type of 'val' in the declaration and in the cast. This could have been avoided if you used cast(typeof(val)), but what if the name of val changes? Then you have the same situation if another variable get's renamed to 'val'. If you use cast(auto) you don't need to maintain the type in both places. It prevents this particular bug. Now I'm not saying that cast(auto) is good in all cases, I'm just trying to get you to see the big picture here. cast(auto) could be useful and could help prevent maintenance bugs in SOME cases. Yes it can be misused, but I don't agree that making it harder to use is a good way to prevent misusage, but requiring more verbosity is good. You may disagree that "cast" is enough verbosity but I think that's a matter of opinion.
Dec 20 2014
parent reply ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sat, 20 Dec 2014 19:26:54 +0000
Jonathan Marler via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 Hmmmm...an interesting concept.  Make unsafe things harder to do=20
 to discourage their use.  I'm not sure if I agree but maybe you=20
 can convince me. Where do you draw the line?
the thing is that they aren't only harder to use, but they are also explicitly marked as "system" things. i.e. things that should be used only if you are *really* know what you're doing. besides, code with `system.cast()` looks suspiciously "burden", which also signals that this is not a thing one should mindlessly use everywhere. something like that.
 is it requires less maintenance. Say you have the following:
=20
 void myfunc(uint x)
 {
      ubyte val;
      //
      // ...
      //
      val =3D cast(ubyte)x;
 }
=20
 Now let's say that you need change the value of 'val' to ushort.
=20
 void myfunc(uint x)
 {
      ushort val;
      //
      // ...
      //
      val =3D cast(ubyte)x;
 }
why do you need `cast` here? isn't `to!ubyte` looks better? and it's not only looks better, it will provide you additional overflow checks too. so if you'll throw a '1024' in your unittest, the second version will fail, signalling that something is going wrong.
 Now I'm not saying that cast(auto) is good in all cases, I'm just=20
 trying to get you to see the big picture here.  cast(auto) could=20
 be useful and could help prevent maintenance bugs in SOME cases.
i see that `cast` should NOT be used in that cases at all. and this returns us to "`cast` is hack. avoid the hacks!"
 Yes it can be misused, but I don't agree that making it harder to=20
 use is a good way to prevent misusage, but requiring more=20
 verbosity is good.  You may disagree that "cast" is enough=20
 verbosity but I think that's a matter of opinion.
sure, i'm just talking about what i see as "good", i'm in no way trying to tell that my opinion is the best one. sorry if my words are too "forcing". i'm a somewhat sarcastic person IRL, and i don't use English in my everyday life, so i can sound too hard sometimes, failing to properly translate my twisted style of writing. ;-)
Dec 20 2014
parent "Jonathan Marler" <johnnymarler gmail.com> writes:
On Saturday, 20 December 2014 at 19:57:54 UTC, ketmar via 
Digitalmars-d wrote:
 On Sat, 20 Dec 2014 19:26:54 +0000
 Jonathan Marler via Digitalmars-d <digitalmars-d puremagic.com> 
 wrote:

 Hmmmm...an interesting concept.  Make unsafe things harder to 
 do to discourage their use.  I'm not sure if I agree but maybe 
 you can convince me. Where do you draw the line?
the thing is that they aren't only harder to use, but they are also explicitly marked as "system" things. i.e. things that should be used only if you are *really* know what you're doing. besides, code with `system.cast()` looks suspiciously "burden", which also signals that this is not a thing one should mindlessly use everywhere. something like that.
 is it requires less maintenance. Say you have the following:
 
 void myfunc(uint x)
 {
      ubyte val;
      //
      // ...
      //
      val = cast(ubyte)x;
 }
 
 Now let's say that you need change the value of 'val' to 
 ushort.
 
 void myfunc(uint x)
 {
      ushort val;
      //
      // ...
      //
      val = cast(ubyte)x;
 }
why do you need `cast` here? isn't `to!ubyte` looks better? and it's not only looks better, it will provide you additional overflow checks too. so if you'll throw a '1024' in your unittest, the second version will fail, signalling that something is going wrong.
Ah yes you are right, to!byte would make more sense because you check at runtime whether or not x is within the range of a byte. This would make the code crash right away instead of having to track down the bug but you still wouldn't see the bug until runtime, and may only happen in rare cases that only occur in the customer environment. to!(typeof(val)) would also handle changing the type when the type of val changes. It looks awkward though. It would be nice if "to" handled type inference. val = to(x); // instead of val = to!(typeof(val)(x); // or val = to!auto(x); // Impossible right now since compiler doesn't understand "to" "val = to!auto(x)" could be useful in some cases but this would be the same basic concept as cast(auto) except "to" allows for more "sanity" checking. I'd have to think more about cases where cast(auto) would be useful but this is starting to take too much of my time so I'll leave that to other people if they want to take time to do so. I've invested enough time into this and if no one else wants to support it then no big deal. Like I said, this would only be a minor convenience.
 Now I'm not saying that cast(auto) is good in all cases, I'm 
 just trying to get you to see the big picture here.  
 cast(auto) could be useful and could help prevent maintenance 
 bugs in SOME cases.
i see that `cast` should NOT be used in that cases at all. and this returns us to "`cast` is hack. avoid the hacks!"
 Yes it can be misused, but I don't agree that making it harder 
 to use is a good way to prevent misusage, but requiring more 
 verbosity is good.  You may disagree that "cast" is enough 
 verbosity but I think that's a matter of opinion.
sure, i'm just talking about what i see as "good", i'm in no way trying to tell that my opinion is the best one. sorry if my words are too "forcing". i'm a somewhat sarcastic person IRL, and i don't use English in my everyday life, so i can sound too hard sometimes, failing to properly translate my twisted style of writing. ;-)
I don't mind your style of writing, some people might be offended by it but it doesn't bother me. When discussing technical details it takes a lot of effort to be polite and I'd rather you spend that effort in making the details more correct rather then trying to be "tactful".
Dec 20 2014
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 18 December 2014 at 22:46:06 UTC, Jonathan Marler 
wrote:
     foo(cast() s);      // Another possible syntax
That already has meaning in D: it strips off qualifiers like casting immutable to mutable. So cast(auto) would be better.
Dec 18 2014