www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - The cast(signed), cast(unsigned) feature proposal

reply "Mrzlga" <bulletproofchest gmail.com> writes:
Hi guys,

This is a small feature proposal.
Please consider to add these to the language:

     cast(signed)
     cast(unsigned)


Motivation:

- To remove the need to write "cast(ulong) x" and repeat the 
underlying type, which is the same motivation as cast(const), 
cast(immutable), cast(shared)

- Reduce the strain of writing signed/unsigned conversions, so 
that making signed/unsigned conversions a compilation error is 
more palatable.

- Works as a new feature: if we have created a function or 
template which uses Concepts to accept just a signed number, we 
can use cast(unsigned) to generically cast any type X to the 
unsigned version.


Positives:

- cast(signed) is easy to type.

- cast(signed) is easy to see -- Scanning over the code with your 
eyes, we can see that the only intention was to make a cast about 
the signedness, but not about anything else.

- Works within the system of grepping for all casts.

- Works in the spirit of 'auto'.

- Consistent with cast(const), cast(immutable), cast(shared).


Downsides:

- Adds two keywords to the language.
     > They aren't the worst keywords, considering that C has them.

- 'unsigned already means something in C, let's not change how it 
works'

- Writing "cast(unsigned) x" is actually more text than 
"cast(ulong) x"
     > True, but the cast(unsigned) expresses the intention


Possible arguments against:

- The idea of 'no casts should be generic'

- Use the library for it and instead make signed(x), unsigned(x) 
templates.

     > Downsides to this solution: User can't easily grep for 
'cast' and find the 'unsigned(x)' template. It should be 
consistently greppable in the exact same way as other casts. 
Because it is a cast, so don't hide it.


That's it!

Thanks for your consideration :)
Jun 07 2013
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 7 June 2013 at 20:52:53 UTC, Mrzlga wrote:
 - Use the library for it and instead make signed(x), 
 unsigned(x) templates.
I think this is a really strong counterargument and one I'd like to see done, along with other kinds of casts in the library.
     > Downsides to this solution: User can't easily grep for 
 'cast' and find the 'unsigned(x)' template. It should be 
 consistently greppable in the exact same way as other casts. 
 Because it is a cast, so don't hide it.
I would name it cast_to_unsigned or signed_cast or something like that. Then the word "cast" is still there. Most of phobos uses camelCase so underscores might be weird, but it is a cast, it is supposed to be a little weird, and besides, I can't get C++'s various_casts out of my mind.
Jun 07 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/7/13 4:52 PM, Mrzlga wrote:
 Hi guys,

 This is a small feature proposal.
 Please consider to add these to the language:

 cast(signed)
 cast(unsigned)
We should prolly add signed() as well. Could you please author an enhancement request (and at best a pull request too)? Thanks, Andrei
Jun 07 2013
next sibling parent reply "Mrzlga" <bulletproofchest gmail.com> writes:
A reason for cast(signed) is to discourage the user from writing:

     cast(int) x;

Because we can't grep for the word "signed",
We have to search for "cast( )" only!

     cast(int) x    // hides the intention, hard to search for!

Yet we can easily grep for:

     cast(signed)
Jun 07 2013
next sibling parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Friday, 7 June 2013 at 21:34:00 UTC, Mrzlga wrote:
 A reason for cast(signed) is to discourage the user from 
 writing:

     cast(int) x;

 Because we can't grep for the word "signed",
 We have to search for "cast( )" only!

     cast(int) x    // hides the intention, hard to search for!

 Yet we can easily grep for:

     cast(signed)
Not convenient, but: cast(Signed!(typeof(x))
Jun 07 2013
parent reply "Idan Arye" <GenericNPC gmail.com> writes:
On Friday, 7 June 2013 at 21:42:05 UTC, Jesse Phillips wrote:
 On Friday, 7 June 2013 at 21:34:00 UTC, Mrzlga wrote:
 A reason for cast(signed) is to discourage the user from 
 writing:

    cast(int) x;

 Because we can't grep for the word "signed",
 We have to search for "cast( )" only!

    cast(int) x    // hides the intention, hard to search for!

 Yet we can easily grep for:

    cast(signed)
Not convenient, but: cast(Signed!(typeof(x))
How about this: if `Foo` is a template with a single type parameter that returns a type, writing `cast(Foo)bar` will be parsed as `cast(Foo!(typeof(bar))bar`. This will allow as to write `cast(Signed)x` - no need for extra keywords - and it will also allow us to write more generic things, like `cast(Nullable)(x)` will return a `typeof(x)` `Nullable` that holds the value of `x` - whatever that value may be. I've written a simple function that does that: auto Cast(alias Template,T)(T source){ return cast(Template!T)(source); } And it works, but not as good as the template solution since `typeof(Cast!Nullable(0))` returns `Template!(int)` instead of `Nullable!(int)`.
Jun 07 2013
next sibling parent "Idan Arye" <GenericNPC gmail.com> writes:
On Friday, 7 June 2013 at 22:05:46 UTC, Idan Arye wrote:
 but not as good as the template solution
Should be "not as good as the syntactic sugar solution"
Jun 07 2013
prev sibling parent reply "Mrzlga" <bulletproofchest gmail.com> writes:
 How about this: if `Foo` is a template with a single type 
 parameter that returns a type, writing `cast(Foo)bar` will be 
 parsed as `cast(Foo!(typeof(bar))bar`.
My proposal has a bad thing about it: The 'unsigned' and 'signed' keywords can't be as easily extended the way that an signed(x) template in the library can: A library author could just specialize the signed() template to add support for their own numeric type. To do the same with cast(signed) it needs to invoke some signed operator on the type, or use your solution. I wanted to deal with the cast(int) x; not showing the intention of "signed". If your cast(SomeTemplate) solution can handle this as well, then it's better. I don't actually mind writing signed(x), but I want to think of a way to discourage people from writing cast(int) x when they are doing nothing but converting unsigned->signed.
Jun 07 2013
parent reply "Mrzlga" <bulletproofchest gmail.com> writes:
"doing nothing but converting unsigned->signed" is a dubious 
statement.

They are still screwing with the range, they are not just "doing 
nothing but converting unsigned->signed".
And 'int' says something about the outcome.

So I am really asking for:

cast(signed int) x;   // make them poor programmers write this, 
lol

That's not what I actually want, but at least it shows: We're 
making a signed conversion, AND we're screwing with the range to 
make it into an int.

for further thought.
Jun 07 2013
next sibling parent reply Timothee Cour <thelastmammoth gmail.com> writes:
I'm against it since we can do it better in library with same efficiency
and better UFCS syntax: see
https://github.com/timotheecour/dtools/blob/master/dtools/util/cast_funs.d

to test it, nothing to install, just type: rdmd --main -unittest
dtools/all.d

here's the unittest:
----
 version(unittest){
    import std.stdio;
    int foo(int x){
        return x;
    }
}
unittest{
    double c;
//    auto b1=cast(int)c.foo;//means cast(int)(c.foo), so would be CT error
    auto b2=(cast(int)c).foo;//verbose syntax: 2 nested parenthesis
    auto b3=c.Cast!int.foo;//simpler syntax

    int a=1;
    auto b=(a+a).Cast!double;
    static assert(is(typeof(b)==double));
    static assert(is(typeof(a.Cast!Immutable)==immutable(int)));
    static assert(is(typeof(a.Cast!Const)==const(int)));
    static assert(is(typeof(0U.Cast!Signed)==int));
    static assert(is(typeof(a.Cast!Unsigned)==uint));
    static assert(is(typeof(a.Cast!Const)==const(int)));
    static assert(is(typeof((a+a).Cast!Unsigned)==uint));
}
----


On Fri, Jun 7, 2013 at 5:43 PM, Mrzlga <bulletproofchest gmail.com> wrote:

 "doing nothing but converting unsigned->signed" is a dubious statement.

 They are still screwing with the range, they are not just "doing nothing
 but converting unsigned->signed".
 And 'int' says something about the outcome.

 So I am really asking for:

 cast(signed int) x;   // make them poor programmers write this, lol

 That's not what I actually want, but at least it shows: We're making a
 signed conversion, AND we're screwing with the range to make it into an int.

 for further thought.
Jun 07 2013
parent reply "Mrzlga" <bulletproofchest gmail.com> writes:
Timothy,

How do you get everyone to use:
     a.Cast!Signed
     a.Cast!Unsigned
     a.Cast!Const
     a.Cast!Immutable
     a.Cast!Shared

And to stop using:
     cast(const)
     cast(immutable)
     cast(shared)
     cast(inout) ?

And have everyone be consistent about it?

Remove the cast() ones from the language?



And what about variations, 'shared const', 'inout shared', etc?

There are some things that should be available to the language, 
even when no modules are imported. I think dealing with the basic 
type system is like that.
Jun 07 2013
parent reply Timothee Cour <thelastmammoth gmail.com> writes:
On Fri, Jun 7, 2013 at 6:53 PM, Mrzlga <bulletproofchest gmail.com> wrote:

 Timothy,

 How do you get everyone to use:
     a.Cast!Signed
     a.Cast!Unsigned
     a.Cast!Const
     a.Cast!Immutable
     a.Cast!Shared

 And to stop using:
     cast(const)
     cast(immutable)
     cast(shared)
     cast(inout) ?

 And have everyone be consistent about it?

 Remove the cast() ones from the language?
not suggesting deprecating cast(), just suggesting there's no need to extend the language as it can be done in library code, advantageously. It's trivially extensible as I wrote it. However, any language extension has to be re-implemented by each compiler implementation.
 And what about variations, 'shared const', 'inout shared', etc?
it's trivial to add to my code a.Cast!"shared const" or a.Cast!SharedConst, etc, as well as more complex ones.
 There are some things that should be available to the language, even when
 no modules are imported. I think dealing with the basic type system is like
 that.
Not if the syntax sugar provided by the language is no simple than that provided by library solution. I've argued library solution is more consistent with UFCS (see my code).
Jun 07 2013
parent reply "Mrzlga" <bulletproofchest gmail.com> writes:
 not suggesting deprecating cast(), just suggesting there's no 
 need to
 extend the language as it can be done in library code, 
 advantageously. It's
 trivially extensible as I wrote it. However, any language 
 extension has to
 be re-implemented by each compiler implementation.
I don't think you can simultaneously try to not-suggest deprecating cast() shortcuts, and do-suggest there's no need to extend the language as it can be done in library code, while suggestiing duplicating cast() shortcuts. Your point would make sense if you were trying to get rid of the shortcuts. Otherwise you should argue for signed(x) / unsigned(x) Make it consistent.
Jun 07 2013
parent Timothee Cour <thelastmammoth gmail.com> writes:
the point is to avoid breaking code.
Since no-one can possibly use cast(unsigned) currently, introducing Cast
and recommending using Cast instead of cast() will not break any code and
provide room for library based cast extensions.

The smaller the symbols in scope and the shorter the syntax the better; I
doubt you're using cast() in all your modules anyways.

However, I very much do support language syntax sugar when it provides
advantages over a library solution:

* tuples (see DIP),
* named parameter argument (see threads)
* and even to some extent := (your suggestion!)

On Fri, Jun 7, 2013 at 7:24 PM, Mrzlga <bulletproofchest gmail.com> wrote:

 not suggesting deprecating cast(), just suggesting there's no need to
 extend the language as it can be done in library code, advantageously.
 It's
 trivially extensible as I wrote it. However, any language extension has to
 be re-implemented by each compiler implementation.
I don't think you can simultaneously try to not-suggest deprecating cast() shortcuts, and do-suggest there's no need to extend the language as it can be done in library code, while suggestiing duplicating cast() shortcuts. Your point would make sense if you were trying to get rid of the shortcuts. Otherwise you should argue for signed(x) / unsigned(x) Make it consistent.
Jun 07 2013
prev sibling parent reply "Idan Arye" <GenericNPC gmail.com> writes:
On Saturday, 8 June 2013 at 00:43:28 UTC, Mrzlga wrote:
 "doing nothing but converting unsigned->signed" is a dubious 
 statement.

 They are still screwing with the range, they are not just 
 "doing nothing but converting unsigned->signed".
 And 'int' says something about the outcome.

 So I am really asking for:

 cast(signed int) x;   // make them poor programmers write this, 
 lol

 That's not what I actually want, but at least it shows: We're 
 making a signed conversion, AND we're screwing with the range 
 to make it into an int.

 for further thought.
So, you want a syntactic salt that will force people to write `cast(singed int)` instead of `cast(int)` and `cast(unsigned int)` instead of `cast(uint)`? What if they are not casting from a number? What if I want the ASCII value of a character - for example, `cast(int)'a'`? Will I have to write `cast(signed int)'a'`, or is this syntactic salt just for casting from numeric types? I'm against this syntactic salt proposal. Programmers should know that `int` is signed and `uint` is unsigend, and I see little point in forcing them to acknowledge that whenever they do a numeric cast. Also, casting to unsigned with implicit type is dangerous, since cast(uint)-1 == 4294967295 != 18446744073709551615 == cast(ulong)-1, but casting to signed is less dangerous, since it only affects large numbers. So the syntactic salt is more important for `cast(uint)` than for `cast(int)` - but `unit` already clarifies that the type is unsigned.
Jun 07 2013
parent reply "Mrzlga" <bulletproofchest gmail.com> writes:
 So, you want a syntactic salt that will force people to write
No, no, I don't actually want the salt. I hoped I had indicated that in my message. It was only for your consideration about cast(int), how it would be nice to "indicate everything" if there was no price to it.
Jun 07 2013
next sibling parent "Mrzlga" <bulletproofchest gmail.com> writes:
I don't know the story of how D resolved to not provide 'ulong' 
and 'unsigned long' as equivalent, but I do understand the 
motivation to keep things short and standard, with 
1-word-per-basic-type.

I should say one thing though,

In C / C++:

unsigned x = f();   // this was traumatic. "unsigned" was an 
actual type itself, not just a type qualifier.
Jun 07 2013
prev sibling next sibling parent reply Timothee Cour <thelastmammoth gmail.com> writes:
not to mention its much harder to implement in language, whereas its
trivial in the library. Also, it makes instrumentation easier, if one wants
to add a callback/logging/breakpoint for a particular cast operation. Seems
much harder with language solution.

On Fri, Jun 7, 2013 at 6:53 PM, Mrzlga <bulletproofchest gmail.com> wrote:

 Timothy,

 How do you get everyone to use:
     a.Cast!Signed
     a.Cast!Unsigned
     a.Cast!Const
     a.Cast!Immutable
     a.Cast!Shared

 And to stop using:
     cast(const)
     cast(immutable)
     cast(shared)
     cast(inout) ?

 And have everyone be consistent about it?

 Remove the cast() ones from the language?
not suggesting deprecating cast(), just suggesting there's no need to extend the language as it can be done in library code, advantageously. It's trivially extensible as I wrote it. However, any language extension has to be re-implemented by each compiler implementation.
 And what about variations, 'shared const', 'inout shared', etc?
it's trivial to add to my code a.Cast!"shared const" or a.Cast!SharedConst, etc, as well as more complex ones.
 There are some things that should be available to the language, even when
 no modules are imported. I think dealing with the basic type system is like
 that.
Not if the syntax sugar provided by the language is no simple than that provided by library solution. I've argued library solution is more consistent with UFCS (see my code).
Jun 07 2013
parent "timotheecour" <timothee.cour2 gmail.com> writes:
On Saturday, 8 June 2013 at 02:21:01 UTC, Timothee Cour wrote:
 not to mention its much harder to implement in language, 
 whereas its
 trivial in the library. Also, it makes instrumentation easier, 
 if one wants
 to add a callback/logging/breakpoint for a particular cast 
 operation. Seems
 much harder with language solution.

 On Fri, Jun 7, 2013 at 6:53 PM, Mrzlga 
 <bulletproofchest gmail.com> wrote:

 Timothy,

 How do you get everyone to use:
     a.Cast!Signed
     a.Cast!Unsigned
     a.Cast!Const
     a.Cast!Immutable
     a.Cast!Shared

 And to stop using:
     cast(const)
     cast(immutable)
     cast(shared)
     cast(inout) ?

 And have everyone be consistent about it?

 Remove the cast() ones from the language?
not suggesting deprecating cast(), just suggesting there's no need to extend the language as it can be done in library code, advantageously. It's trivially extensible as I wrote it. However, any language extension has to be re-implemented by each compiler implementation.
 And what about variations, 'shared const', 'inout shared', etc?
it's trivial to add to my code a.Cast!"shared const" or a.Cast!SharedConst, etc, as well as more complex ones.
 There are some things that should be available to the 
 language, even when
 no modules are imported. I think dealing with the basic type 
 system is like
 that.
Not if the syntax sugar provided by the language is no simple than that provided by library solution. I've argued library solution is more consistent with UFCS (see my code).
not to mention its much harder and bug-prone to implement in language, whereas its trivial in the library. Also, it makes instrumentation easier, if one wants to add a callback/logging/breakpoint for a particular cast operation. Seems much harder with language solution.
Jun 07 2013
prev sibling parent reply "Idan Arye" <GenericNPC gmail.com> writes:
On Saturday, 8 June 2013 at 01:58:46 UTC, Mrzlga wrote:
 So, you want a syntactic salt that will force people to write
No, no, I don't actually want the salt. I hoped I had indicated that in my message. It was only for your consideration about cast(int), how it would be nice to "indicate everything" if there was no price to it.
So, let me get this straight: * You don't want `cast(signed)`, because of the range difference between the types. * You want `cast(signed int)` but not as syntactic salt - which means you still want `cast(int)` to work. How about `cast(/*signed*/ int)`?
Jun 07 2013
parent "Mrzlga" <bulletproofchest gmail.com> writes:
 So, let me get this straight:

  * You don't want `cast(signed)`, because of the range 
 difference between the types.
  * You want `cast(signed int)` but not as syntactic salt - 
 which means you still want `cast(int)` to work.

 How about `cast(/*signed*/ int)`?
- I do want cast(signed) - I don't want to suggest cast(int) should not work, but rather to think of a solution for better documentation in the code, and to encourage people to write: cast(signed) // when they're casting unsigned->signed cast(int) // when they're casting short->int - I still feel slightly uneasy about the previous point. What I mentioned about cast(signed int) was a form of brainstorming. I wanted to try to give some consideration to people who'd want the destination datatype to be explicit, as it says something about the destination range. However, the fact that we must be careful of the range is already implied by cast(signed) and cast(unsigned). - I like how cast(const) uses the lowercase const and the same const keyword. There's a nice consistency about that. So I don't want them in the library. - Cast operations should be available without module imports. - I would use the cast(signed) and feel comfortable. - I could use the signed(x) and enjoy it! cast(signed) is not a super important thing like the := - I think *your* idea was good and possibly better than mine, as it allows library authors to create new numerical types that support signed/unsigned casting, and yet still access it via cast(signed) if 'signed' was the template. - I'm not sure if Walter & Andrei would want cast(ToWorkWithTheTemplates). Regards, z
Jun 07 2013
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 6/7/2013 2:33 PM, Mrzlga wrote:
 Yet we can easily grep for:
      cast(signed)
Not/*"*/"*/that easy
Jun 07 2013
prev sibling next sibling parent reply "Mrzlga" <bulletproofchest gmail.com> writes:
Andrei, what do you think about the unsigned(x) not showing up on 
greps for 'cast'? No problem? Is the grep irrelevant? Not all 
casts should be marked as a cast?

People told me the grepping was important, so I tried to work 
their idea in.


I understand, you can still search for:
"signed("                     // signed or unsigned
"cast(u"                      // unsigned
"cast( ... every type ... )"  // trying to find signed conversions


But I was trying to make the thing more predictable altogether.
Jun 07 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 6/7/13 5:41 PM, Mrzlga wrote:
 Andrei, what do you think about the unsigned(x) not showing up on greps
 for 'cast'? No problem? Is the grep irrelevant? Not all casts should be
 marked as a cast?

 People told me the grepping was important, so I tried to work their idea
 in.


 I understand, you can still search for:
 "signed(" // signed or unsigned
 "cast(u" // unsigned
 "cast( ... every type ... )" // trying to find signed conversions


 But I was trying to make the thing more predictable altogether.
Grepping is useful for identifying dangerous patterns. What a dangerous pattern is varies according to the person, but it's not possible to grep for everything that everyone considers dangerous. Andrei
Jun 07 2013
prev sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Fri, 07 Jun 2013 17:03:47 -0400
schrieb Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:

 On 6/7/13 4:52 PM, Mrzlga wrote:
 Hi guys,

 This is a small feature proposal.
 Please consider to add these to the language:

 cast(signed)
 cast(unsigned)
We should prolly add signed() as well. Could you please author an enhancement request (and at best a pull request too)? Thanks, Andrei
That made me scratch my head again. I thought std.traits contains non-modifying queries into the type system and std.typecons contains the _actions_ for type system trickery. In any case I wouldn't have searched std.traits for a function that gets stuff done. On the topic, I think that D's cast() does too many things in one. You can _accidentally_ cast away immutable for example and run into undefined behavior as per the language specs. At first I liked how D got rid of C's different casts, but on the long run it is too pragmatic for my taste. -- Marco
Jun 07 2013
prev sibling next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Friday, 7 June 2013 at 20:52:53 UTC, Mrzlga wrote:
 That's it!

 Thanks for your consideration :)
FWI, you can use std.trait's Signed and Unsigned as a partial alternative. IMO, not quite as elegant. I support this syntax. It's natural, and I *think* the "keywords" are reserved anyways, so that shouldn't be a problem anyways. We already have "cast(const)" anyways, so cast(signed) is (imo) only natural. I'd almost expect it to work. I think this isn't the first time it has been brought up either. Unless I'm mistaken, user Bearophile has opened a request for this. Not 100% sure though. Gonna look for it.
Jun 07 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Friday, 7 June 2013 at 21:04:40 UTC, monarch_dodra wrote:
 On Friday, 7 June 2013 at 20:52:53 UTC, Mrzlga wrote:
 That's it!

 Thanks for your consideration :)
FWI, you can use std.trait's Signed and Unsigned as a partial alternative. IMO, not quite as elegant. I support this syntax. It's natural, and I *think* the "keywords" are reserved anyways, so that shouldn't be a problem anyways. We already have "cast(const)" anyways, so cast(signed) is (imo) only natural. I'd almost expect it to work. I think this isn't the first time it has been brought up either. Unless I'm mistaken, user Bearophile has opened a request for this. Not 100% sure though. Gonna look for it.
EDIT: Couldn't find it. Must have been my imagination. Didn't realize we had "signed" too (as opposed to "Signed"), so I'm not sure how useful that would be actually. I still find it idiomatic though.
Jun 07 2013
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Friday, 7 June 2013 at 20:52:53 UTC, Mrzlga wrote:
 - Use the library for it and instead make signed(x), 
 unsigned(x) templates.
This !
Jun 08 2013