Jump to page: 1 2
Thread overview
[Issue 18945] immutable variable is used as if it's an enum
Jun 05, 2018
Jonathan M Davis
Jun 05, 2018
David Bennett
Jun 05, 2018
Jonathan M Davis
Jun 05, 2018
David Bennett
Jun 05, 2018
anonymous4
Jun 05, 2018
Jonathan M Davis
Jun 05, 2018
David Bennett
Jun 05, 2018
David Bennett
Jun 05, 2018
David Bennett
Jun 05, 2018
ag0aep6g
Jun 06, 2018
Simen Kjaeraas
Jun 06, 2018
David Bennett
Dec 17, 2022
Iain Buclaw
June 05, 2018
https://issues.dlang.org/show_bug.cgi?id=18945

Jonathan M Davis <issues.dlang@jmdavisProg.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |issues.dlang@jmdavisProg.co
                   |                            |m

--- Comment #1 from Jonathan M Davis <issues.dlang@jmdavisProg.com> ---
Yeah. And bizarrely, this code actually results in an error about not being able to call stuff during CTFE:

int foo()
{
    import std.datetime;
    return cast(int)Clock.currTime().stdTime;
}

void main()
{
    immutable i = foo();
    int[i] arr;
}

Getting rid of the declaration for arr fixes the problem. So, clearly, the compiler is currently deciding whether it should do CTFE on an immutable, local variable based on whether it's then used in a context where its value must be known at compile time instead of forcing enum to be used instead. It also seems to do the same with const.

The fact that the static array's size can use a local variable is completely inconsistent with how CTFE normally works and makes the whole situation that much more confusing. CTFE should only be kicking in based on whether the value is actually needed at compile time and not based on whether the variable that it's assigned to is then used at compile time.

--
June 05, 2018
https://issues.dlang.org/show_bug.cgi?id=18945

--- Comment #2 from David Bennett <davidbennett@bravevision.com> ---
Disclaimer: Just a D user, I hold no decision making power or insight into the history here.

const and immutable are runtime lvalues that have a known way to get "a" value at compiletime. As you have noticed the runtime and compiletime values could be different. Here is another example to show the same effect.

---
unittest {
    immutable n = __ctfe ? 1 : 2;
    enum j = n;
    assert(n == j);
}
---

If you wanted to opt-in to making sure you could only use n at runtime you could make it a `static immutable` but this has the effect of running the assignment expression at compiletime.

I believe the current functionality is being used in various projects so I dont see this being changed without at least a deprecation process. For example, I've seen sending const variables as template parameters more than a few times.

As for my personal opinion on this issue, I believe using const and immutable at compiletime is useful, it's just that the values could be different that's confusing.

So I believe the current reasoning goes like this:
    immutable values are theoretically known at compile time so why not use
them.
    It's not always possible to ctfe so runtime immutable is assigned at
runtime.
    But the runtime value is not known at compiletime, so when it's used we do
the ctfe then and error if it cant.

--
June 05, 2018
https://issues.dlang.org/show_bug.cgi?id=18945

--- Comment #3 from Jonathan M Davis <issues.dlang@jmdavisProg.com> ---
This probably does need to be removed via deprecation rather than simply making it an error, but allowing it is exactly the sort of thing that increases the confusion about how CTFE works and when it's used. Currently,

    immutable i = foo();

doesn't do CTFE. But

    immutable i = foo();
    int[i] arr;

does, and that muddies the waters considerably. We already have problems due to folks getting really confused about why stuff like

    auto foo(int i)
    {
        return bar!i();
    }

isn't legal, and allowing a runtime variable to be used just because it's immutable makes that worse - even more so when you consider that

    auto foo(immutable int i)
    {
        return bar!i();
    }

won't work, and neither will

    auto foo(immutable int i = 42)
    {
        return bar!i();
    }

And allowing

    immutable i = foo();
    int[i] arr;

to work doesn't even buy us anything. You could simply use enum instead of immutable, and it works perfectly fine.

My guess is that the current behavior was added because of an enhancement request, and the person who implemented it didn't think of all of the consequences that result from that decision (including the issue with __ctfe). But I definitely think that we'd be better off if you _had_ to use an enum in this case and that the fact that a variable was const or immutable would have zero effect on CTFE.

--
June 05, 2018
https://issues.dlang.org/show_bug.cgi?id=18945

David Bennett <davidbennett@bravevision.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |davidbennett@bravevision.co
                   |                            |m

--- Comment #4 from David Bennett <davidbennett@bravevision.com> ---
I'm not sure what workaround we would recommend in the deprecation messaged as the current functionality is actually hard to replicate... as enum and static would give a different runtime result (actually an error in this case as __ctfe is not known at statictime... only ctfetime and runtime)

The best I could do on short notice was:

unittest {
    immutable n = __ctfe ? 1 : 2;
    enum l = {return __ctfe ? 1 : 2;}();
    int[l] a;
    assert(a.length == n);
}

--
June 05, 2018
https://issues.dlang.org/show_bug.cgi?id=18945

anonymous4 <dfj1esp02@sneakemail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Hardware|x86                         |All
                 OS|Windows                     |All

--- Comment #5 from anonymous4 <dfj1esp02@sneakemail.com> ---
---
int f(in int a) pure
{
    return a;
}

void g()
{
    immutable int a=0;
    static assert(f(a)==0);
}
---
This works.


---
int f(in ref int a) pure
{
    return a;
}

void g()
{
    immutable int a=0;
    static assert(f(a)==0);
}
---
This doesn't.

--
June 05, 2018
https://issues.dlang.org/show_bug.cgi?id=18945

--- Comment #6 from Jonathan M Davis <issues.dlang@jmdavisProg.com> ---
(In reply to David Bennett from comment #4)
> I'm not sure what workaround we would recommend in the deprecation messaged as the current functionality is actually hard to replicate.

Just use an enum if you want the value to be known and used at compile time, and use an immutable variable if you want it to be known and used at runtime. Don't try to have a variable with different values at compile time and runtime. And if for some reason, you want the value calculated at compile time but to still have a variable, then use an enum to initialize the immutable variable. That's what you have to do with mutable variables already.

--
June 05, 2018
https://issues.dlang.org/show_bug.cgi?id=18945

--- Comment #7 from David Bennett <davidbennett@bravevision.com> ---
(In reply to Jonathan M Davis from comment #6)
> 
> Just use an enum if you want the value to be known and used at compile time, and use an immutable variable if you want it to be known and used at runtime. Don't try to have a variable with different values at compile time and runtime. And if for some reason, you want the value calculated at compile time but to still have a variable, then use an enum to initialize the immutable variable. That's what you have to do with mutable variables already.

So the deprecation message shouldn't have a concrete example to opt-in to keep
the current functionality.
Just something like "Deprecation: Using an immutable variable at compile time
will be removed in a future version. Try changing `n` in `int[n] a;` to use an
enum variable.".
And assume D users will know that they will need to implement the enum
separately from the immutable if they want to keep the status quo?

Then there are immutable struct members used at compile time, they might not be
easy to convert to an enum.
https://run.dlang.io/is/cfGfxw
I've never seen it used like that... but it does work currently.

--
June 05, 2018
https://issues.dlang.org/show_bug.cgi?id=18945

--- Comment #8 from David Bennett <davidbennett@bravevision.com> ---
(In reply to David Bennett from comment #7)
> Then there are immutable struct members used at compile time, they might not
> be easy to convert to an enum.
> https://run.dlang.io/is/cfGfxw
> I've never seen it used like that... but it does work currently.

Actually, I reduced that last case a bit to much that it would work fine even with this change...

--
June 05, 2018
https://issues.dlang.org/show_bug.cgi?id=18945

--- Comment #9 from David Bennett <davidbennett@bravevision.com> ---
(In reply to David Bennett from comment #8)
> (In reply to David Bennett from comment #7)
> > Then there are immutable struct members used at compile time, they might not
> > be easy to convert to an enum.
> > https://run.dlang.io/is/cfGfxw
> > I've never seen it used like that... but it does work currently.
> 
> Actually, I reduced that last case a bit to much that it would work fine even with this change...

Here is the case I was thinking of: https://run.dlang.io/is/zZWdIQ

Only works currently with static immutable, so not sure if it could be a problem as I think this change would only effect immutable (without static). sorry for the noise.

--
June 05, 2018
https://issues.dlang.org/show_bug.cgi?id=18945

ag0aep6g <ag0aep6g@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |ag0aep6g@gmail.com

--
« First   ‹ Prev
1 2