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 :)

- 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.

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)

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)

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)`.

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.

"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.

"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.

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.

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 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.

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.

"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.

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.

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.

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 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.

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)`?

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

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.

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

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

FWI, you can use std.trait's Signed and Unsigned as a partial
alternative.
http://dlang.org/phobos/std_traits.html#.Signed
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.

FWI, you can use std.trait's Signed and Unsigned as a partial
alternative.
http://dlang.org/phobos/std_traits.html#.Signed
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.