Thread overview
Tired by deprecation message for unary operators on 8/16 bit vars ? A simple solution
Jun 07, 2018
Basile B.
Jun 07, 2018
H. S. Teoh
Jun 07, 2018
Basile B.
Jun 07, 2018
H. S. Teoh
Jun 07, 2018
Johan Engelen
Jun 07, 2018
H. S. Teoh
June 07, 2018
I don't know if this is a bug but this works:

```
module runnable;

struct Byte { byte value; alias value this;}

void main()
{
    {Byte b; auto c = ~b;} // no message
    {byte b; auto c = ~b;} // deprecation...
}
```

---
Baz
June 07, 2018
On Thu, Jun 07, 2018 at 01:42:17PM +0000, Basile B. via Digitalmars-d wrote:
> I don't know if this is a bug but this works:
> 
> ```
> module runnable;
> 
> struct Byte { byte value; alias value this;}
> 
> void main()
> {
>     {Byte b; auto c = ~b;} // no message
>     {byte b; auto c = ~b;} // deprecation...
> }
> ```
[...]

You're on the right track. Now all you have to do is to add operator overloading to make the wrapper type infectious, and a convenience function that can be easily typed, and you get:

-------
/**
 * Truncating wrapper around built-in narrow ints to work around stupid casts.
 */
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 ~ "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

-- 
Public parking: euphemism for paid parking. -- Flora
June 07, 2018
On Thursday, 7 June 2018 at 15:18:49 UTC, H. S. Teoh wrote:
> On Thu, Jun 07, 2018 at 01:42:17PM +0000, Basile B. via Digitalmars-d wrote:
>> [...]
> [...]
>
> You're on the right track. Now all you have to do is to add operator overloading to make the wrapper type infectious, and a convenience function that can be easily typed, and you get:
>
> [...]

Yeah nice, but it can be more simply used _just_ when the unary operator would lead to the message (with ctor: ~SomeType(...).
June 07, 2018
On Thu, Jun 07, 2018 at 03:52:10PM +0000, Basile B. via Digitalmars-d wrote:
> On Thursday, 7 June 2018 at 15:18:49 UTC, H. S. Teoh wrote:
> > On Thu, Jun 07, 2018 at 01:42:17PM +0000, Basile B. via Digitalmars-d wrote:
> > > [...]
> > [...]
> > 
> > You're on the right track. Now all you have to do is to add operator overloading to make the wrapper type infectious, and a convenience function that can be easily typed, and you get:
> > 
> > [...]
> 
> Yeah nice, but it can be more simply used _just_ when the unary
> operator would lead to the message (with ctor: ~SomeType(...).

The same deprecation message appears when doing simple arithmetic with narrow int types, like `byte b = cast(byte) 10 + cast(byte) 20;`. The .np wrapper gets rid of all that, with the added bonus of documenting the programmer's intent in the code.


T

-- 
English is useful because it is a mess. Since English is a mess, it maps well onto the problem space, which is also a mess, which we call reality. Similarly, Perl was designed to be a mess, though in the nicest of all possible ways. -- Larry Wall
June 07, 2018
On Thursday, 7 June 2018 at 15:18:49 UTC, H. S. Teoh wrote:
>
> Now all you have to do is to add operator overloading to make the wrapper type infectious, and a convenience function that can be easily typed, and you get:

[...]

I'd like to have this in the stdlib, what are the chances?

-Johan

June 07, 2018
On Thu, Jun 07, 2018 at 05:02:09PM +0000, Johan Engelen via Digitalmars-d wrote:
> On Thursday, 7 June 2018 at 15:18:49 UTC, H. S. Teoh wrote:
> > 
> > Now all you have to do is to add operator overloading to make the wrapper type infectious, and a convenience function that can be easily typed, and you get:
> 
> [...]
> 
> I'd like to have this in the stdlib, what are the chances?
[...]

Just copy-n-paste my code into your local Phobos repo and submit a PR. ;-)


T

-- 
Creativity is not an excuse for sloppiness.