Jump to page: 1 24  
Page
Thread overview
Why does intpromote spew warnings for ~ operator?
Sep 12, 2021
Walter Bright
Sep 13, 2021
Alexey
Sep 13, 2021
Walter Bright
Sep 13, 2021
Walter Bright
Sep 16, 2021
Walter Bright
Sep 13, 2021
Dennis
Sep 13, 2021
H. S. Teoh
Sep 13, 2021
Paul Backus
Sep 13, 2021
jfondren
Sep 13, 2021
H. S. Teoh
Sep 13, 2021
H. S. Teoh
Sep 13, 2021
Guillaume Piolat
Sep 13, 2021
Alexey
Sep 14, 2021
bauss
Sep 14, 2021
Alexey
Sep 14, 2021
jfondren
Sep 14, 2021
Alexey
Sep 14, 2021
Mike Parker
Sep 14, 2021
Dukc
Sep 14, 2021
Alexey
Sep 14, 2021
Stefan Koch
Sep 14, 2021
H. S. Teoh
Sep 14, 2021
Paul Backus
Sep 14, 2021
Guillaume Piolat
Sep 14, 2021
Adam D Ruppe
September 12, 2021
import std.stdio;
import std.meta;
void main()
{
    int nbad;
    foreach(T; AliasSeq!(short, ushort))
    {
        foreach(int i; T.min .. T.max + 1)
        {
            T x = cast(T)i;
            T y = ~x;
            T newy = cast(T)~cast(int)x;
            if(y != newy)
            {
                writefln("%s: x: %s, y: %s, newy: %s", T.stringof, x, y, newy);
                ++nbad;
            }
        }
    }
    writeln("Number of affected cases: ", nbad);
}

Output:

onlineapp.d(11): Deprecation: integral promotion not done for `~x`, use '-preview=intpromote' switch or `~cast(int)(x)`
onlineapp.d(11): Deprecation: integral promotion not done for `~x`, use '-preview=intpromote' switch or `~cast(int)(x)`
Number of affected cases: 0

Note that with -de these become errors. With the -preview=intpromote switch, the uncasted negation compiles and runs as expected.

Right now, the deprecation is telling users under penalty of not compiling to do something that will achieve nothing when intpromote is enabled.

-Steve

September 12, 2021
On 9/12/2021 7:14 AM, Steven Schveighoffer wrote:
> Right now, the deprecation is telling users *under penalty of not compiling* to do something that will achieve nothing when intpromote is enabled.

The question for ~x is to promote x to an int and then complement, or complement and then promote.. Those are not equivalent.

The idea is to move towards doing it the C way, which is promote and then complement.

September 13, 2021

On Sunday, 12 September 2021 at 18:13:14 UTC, Walter Bright wrote:

>

On 9/12/2021 7:14 AM, Steven Schveighoffer wrote:

>

Right now, the deprecation is telling users under penalty of not compiling to do something that will achieve nothing when intpromote is enabled.

The question for ~x is to promote x to an int and then complement, or complement and then promote.. Those are not equivalent.

The idea is to move towards doing it the C way, which is promote and then complement.

But is this really ok to change variable size for simple bit flipping? maybe there should be exception at least for ~ operation?


void main()
{
    ushort a  = 0b100;
    ushort b  = ~a;
}

t.d(5): Deprecation: integral promotion not done for `~a`, use '-preview=intpromote' switch or `~cast(int)(a)`

September 13, 2021
On 9/12/2021 11:12 PM, Alexey wrote:
> But is this really ok to change variable size for simple bit flipping?

The idea is that C like expressions should behave like C.
September 13, 2021

On 9/12/21 2:13 PM, Walter Bright wrote:

>

On 9/12/2021 7:14 AM, Steven Schveighoffer wrote:

>

Right now, the deprecation is telling users under penalty of not compiling to do something that will achieve nothing when intpromote is enabled.

The question for ~x is to promote x to an int and then complement, or complement and then promote.. Those are not equivalent.

The idea is to move towards doing it the C way, which is promote and then complement.

I'm fine with the C way, I'm fine with what intpromote is trying to accomplish.

Yet, maybe you didn't understand what my point is.

This code:

short s = 5;
short t = ~s;
writeln("t is ", t);

Compile without -preview=intpromote, you get the output:

onlineapp.d(6): Deprecation: integral promotion not done for `~s`, use '-preview=intpromote' switch or `~cast(int)(s)`
t is -6

Compile with -preview=intpromote, you get the output:

t is -6

In other words, the deprecation is suggesting I do something that is unnecessary. That's a terrible message to send.

Now, in my original rant, I erred in saying that ushort also works like this -- it doesn't. ushort requires a cast because ~cast(int)someUshort is not going to fit into a ushort. I could have sworn I tested this, but it definitely fails without the cast.

However, the larger point, which I talked about last year, is that anyone who has this code is going to be super-annoyed that they have to insert casts. If they want to get rid of the deprecation they need to insert two casts, one which can be removed after adding intpromote. But the point is that if you are assigning a small int to the result of another small int negation or complement, the intpromote rules don't fix anything. They just get in the way.

But this time, I'll just focus on the ~short, (and ~byte) which should be assignable to its own type, regardless of whether you promote first or not.

I think we can have a solution that allows code that behaves the same to continue to compile without deprecation, while deprecating the code that will change with -preview=intpromote.

-Steve

September 13, 2021

On 9/13/21 3:41 AM, Walter Bright wrote:

>

On 9/12/2021 11:12 PM, Alexey wrote:

>

But is this really ok to change variable size for simple bit flipping?

The idea is that C like expressions should behave like C.

C allows exactly what he wrote, and it already works the same as it does in C.

-Steve

September 13, 2021

On Monday, 13 September 2021 at 11:41:29 UTC, Steven Schveighoffer wrote:

>

I think we can have a solution that allows code that behaves the same to continue to compile without deprecation, while deprecating the code that will change with -preview=intpromote.

It could also help with finally turning it into an error and then making it the default. It's been almost 4 years now since the Pull Request introducing it was merged.

September 13, 2021

On 9/12/21 10:14 AM, Steven Schveighoffer wrote:

>

With the -preview=intpromote switch, the uncasted negation compiles and runs as expected.

I thought I had tested this, but I must have been wrong. With -preview=intpromote, only the short version compiles, the ushort version complains that you can't fit an int into a ushort.

Which is unfortunate, because most people would not use bitwise negate on a short, they would do it on a ushort.

Still, I feel like D should allow what C allows here (and what currently working code expects).

-Steve

September 13, 2021
On Sun, Sep 12, 2021 at 10:14:03AM -0400, Steven Schveighoffer via Digitalmars-d wrote: [...]
> ```
> onlineapp.d(11): Deprecation: integral promotion not done for `~x`, use
> '-preview=intpromote' switch or `~cast(int)(x)`
> onlineapp.d(11): Deprecation: integral promotion not done for `~x`, use
> '-preview=intpromote' switch or `~cast(int)(x)`
> Number of affected cases: 0
> ```
[...]

The integer promotion situation in D is a mess.  My personal preference is:

--------
module nopromote;

enum isNarrowInt(T) = is(T : int) || is(T : uint);

/**
 * A wrapper around a built-in narrow int that truncates the result of
 * arithmetic operations to the narrow type, overriding built-in int promotion
 * rules.
 */
struct Np(T)
    if (isNarrowInt!T)
{
    T impl;
    alias impl this;

    /**
     * Truncating binary operator.
     */
    Np opBinary(string op, U)(U u)
        if (is(typeof((T x, U y) => mixin("x " ~ op ~ " y"))))
    {
        return Np(cast(T) mixin("this.impl " ~ op ~ " u"));
    }

    /**
     * Truncating unary operator.
     */
    Np opUnary(string op)()
        if (is(typeof((T x) => mixin(op ~ "cast(int) x"))))
    {
        return Np(cast(T) mixin(op ~ " cast(int) this.impl"));
    }

    /**
     * Infectiousness: any expression containing Np should automatically use Np
     * operator semantics.
     */
    Np opBinaryRight(string op, U)(U u)
        if (is(typeof((T x, U y) => mixin("x " ~ op ~ " y"))))
    {
        return Np(cast(T) mixin("u " ~ op ~ " this.impl"));
    }
}

/**
 * Returns: A lightweight wrapped type that overrides built-in arithmetic
 * operators to always truncate to the given type without promoting to int or
 * uint.
 */
auto np(T)(T t)
    if (isNarrowInt!T)
{
    return Np!T(t);
}

// Test binary ops
@safe unittest
{
    ubyte x = 1;
    ubyte y = 2;
    auto z = x.np + y;
    static assert(is(typeof(z) : ubyte));
    assert(z == 3);

    byte zz = x.np + y;
    assert(zz == 3);

    x = 255;
    z = x.np + y;
    assert(z == 1);
}

@safe unittest
{
    byte x = 123;
    byte y = 5;
    auto z = x.np + y;
    static assert(is(typeof(z) : byte));
    assert(z == byte.min);

    byte zz = x.np + y;
    assert(zz == byte.min);
}

@safe unittest
{
    import std.random;
    short x = cast(short) uniform(0, 10);
    short y = 10;
    auto z = x.np + y;
    static assert(is(typeof(z) : short));
    assert(z == x + 10);

    short s = x.np + y;
    assert(s == x + 10);
}

// Test unary ops
@safe unittest
{
    byte b = 10;
    auto c = -b.np;
    static assert(is(typeof(c) : byte));
    assert(c == -10);

    ubyte ub = 16;
    auto uc = -ub.np;
    static assert(is(typeof(uc) : ubyte));
    assert(uc == 0xF0);
}
--------

;-)


T

-- 
Let's call it an accidental feature. -- Larry Wall
September 13, 2021
On Monday, 13 September 2021 at 15:38:44 UTC, H. S. Teoh wrote:
>
> The integer promotion situation in D is a mess.  My personal preference is:
>
> --------
> module nopromote;
>
> [...]

Have you considered putting this up on code.dlang.org? Probably easier for people to find it there than by searching through old forum posts.
« First   ‹ Prev
1 2 3 4