Thread overview
Easy way to accept X and immutable X in parameters without overloading?
Jan 11, 2021
Jack
Jan 11, 2021
ag0aep6g
Jan 11, 2021
Jack
Jan 11, 2021
ag0aep6g
Jan 11, 2021
Jack
Jan 11, 2021
ag0aep6g
Jan 11, 2021
Paul Backus
January 11, 2021
let's say a I have this:

void f(X foo) { }

but I'd like to make f() accept immutable X too so instead of cast away everywhere in the code where immutable(X) is passed to f() or make a overload for this, are there any way to accept both in same function? those function are callback-like functions, I have lots of them so already and would need to double, if I do add an overload just for the immutable. I did come up with something using templates, not sure if it's ugly:

void f(T)(T x)
if(is(T == C) || is(T == immutable(C)) {
// ...
}
January 11, 2021
On Monday, 11 January 2021 at 16:40:01 UTC, Jack wrote:
> let's say a I have this:
>
> void f(X foo) { }
>
> but I'd like to make f() accept immutable X too so instead of cast away everywhere in the code where immutable(X) is passed to f() or make a overload for this, are there any way to accept both in same function? those function are callback-like functions, I have lots of them so already and would need to double, if I do add an overload just for the immutable. I did come up with something using templates, not sure if it's ugly:
>
> void f(T)(T x)
> if(is(T == C) || is(T == immutable(C)) {
> // ...
> }

Accepting both mutable and immutable is what `const` is for:

void f(const X foo) { ... }
January 11, 2021
On Monday, 11 January 2021 at 16:56:05 UTC, ag0aep6g wrote:
> On Monday, 11 January 2021 at 16:40:01 UTC, Jack wrote:
>> let's say a I have this:
>>
>> void f(X foo) { }
>>
>> but I'd like to make f() accept immutable X too so instead of cast away everywhere in the code where immutable(X) is passed to f() or make a overload for this, are there any way to accept both in same function? those function are callback-like functions, I have lots of them so already and would need to double, if I do add an overload just for the immutable. I did come up with something using templates, not sure if it's ugly:
>>
>> void f(T)(T x)
>> if(is(T == C) || is(T == immutable(C)) {
>> // ...
>> }
>
> Accepting both mutable and immutable is what `const` is for:
>
> void f(const X foo) { ... }

thanks! now, how would I add const here?

import std.container : SList;
auto l = SList!Callabck();

doesn't work:

auto l = SList!(const(Callabck()));
auto l = SList!(const Callabck());



January 11, 2021
On Monday, 11 January 2021 at 18:12:17 UTC, Jack wrote:
> thanks! now, how would I add const here?
>
> import std.container : SList;
> auto l = SList!Callabck();
>
> doesn't work:
>
> auto l = SList!(const(Callabck()));
> auto l = SList!(const Callabck());

You said you want the callbacks to accept both mutable and immutable. So make the parameter `const` in the callback type:

    alias Callabck = void function(const X foo);

If you wanted an `SList` of `const Callabck`s, you'd write that like so:

    auto l = SList!(const Callabck)();

But it seems like `SList` doesn't support const elements. And I don't think that's what you actually want anyways.

(By the way, you've got a typo there in "Callabck".)
January 11, 2021
On Monday, 11 January 2021 at 18:37:58 UTC, ag0aep6g wrote:
> On Monday, 11 January 2021 at 18:12:17 UTC, Jack wrote:
>> thanks! now, how would I add const here?
>>
>> import std.container : SList;
>> auto l = SList!Callabck();
>>
>> doesn't work:
>>
>> auto l = SList!(const(Callabck()));
>> auto l = SList!(const Callabck());
>
> You said you want the callbacks to accept both mutable and immutable. So make the parameter `const` in the callback type:
>
>     alias Callabck = void function(const X foo);

I did exactly that and SList template initilization failed

> If you wanted an `SList` of `const Callabck`s, you'd write that like so:
>
>     auto l = SList!(const Callabck)();
>
> But it seems like `SList` doesn't support const elements. And I don't think that's what you actually want anyways.

What I want is store a instance of Callback, whose parameter accept both immutable and non-immutable (so I used const) in the SList but it failed to initialize

>
> (By the way, you've got a typo there in "Callabck".)

oh i see but I did write this code just for this post anyway.

Here's what I'm trying to make to work:

import std.container : SList;

class C
{
    static immutable Foo = new C();
   // ....
}

alias Callback = void function(const C, int);

void main()
{
    auto l = SList!Callback();
    auto a = (C c, int d) { };
    auto b = (C c, int d) { };
    auto c = (const C c, int d) { };
    l.insert(a);
    l.insert(b);
    l.insert(c);
}



January 11, 2021
On Monday, 11 January 2021 at 18:51:04 UTC, Jack wrote:
> Here's what I'm trying to make to work:
>
> import std.container : SList;
>
> class C
> {
>     static immutable Foo = new C();
>    // ....
> }
>
> alias Callback = void function(const C, int);
>
> void main()
> {
>     auto l = SList!Callback();
>     auto a = (C c, int d) { };
>     auto b = (C c, int d) { };
>     auto c = (const C c, int d) { };
>     l.insert(a);
>     l.insert(b);
>     l.insert(c);
> }

I'm assuming that you then want to call the callbacks on mutable and immutable `C`s like `C.Foo`.

You have to add `const` to the `a` and `b` functions, too:

    auto a = (const C c, int d) { };
    auto b = (const C c, int d) { };

Without those `const`s, you have callbacks with mutable parameters being called on an immutable object. That cannot work.
January 11, 2021
On Monday, 11 January 2021 at 18:51:04 UTC, Jack wrote:
> alias Callback = void function(const C, int);
>
> void main()
> {
>     auto l = SList!Callback();
>     auto a = (C c, int d) { };
>     auto b = (C c, int d) { };
>     auto c = (const C c, int d) { };
>     l.insert(a);
>     l.insert(b);
>     l.insert(c);
> }

You have a type mismatch. Changing the code to use explicit type annotations instead of `auto` makes the problem obvious:

alias Callback = void function(const C, int);

void main()
{
    Callback a = (C c, int d) { }; // Error
    Callback b = (C c, int d) { }; // Error
    Callback c = (const C c, int d) { };
}

The error message given is the same for both lines:

Error: cannot implicitly convert expression `__lambda1` of type `void function(C c, int d) pure nothrow @nogc @safe` to `void function(const(C), int)`

In other words, `a` and `b` are not valid Callbacks, because they take a mutable C argument instead of a const C argument.