Const variables - Variables that can be set only once

536 views
Skip to first unread message

smisra

unread,
Apr 3, 2013, 4:21:02 AM4/3/13
to std-dis...@isocpp.org
Hi,
I have seen in a lot of places code like

int i;
if(someConditionIstrue)
{
Do some operations and calculate the value of i;
i = some calculated value;
}

use i; //Note this value is only used not changed. It should not be changed.
But unfortunately in this case there is no way to guarantee it.
so now if some one comes and does

i = 10;// This is valid

What i was thinking: is there a way to tell that "i" can be set only once?
After that it will be a constant. Something like

const once int i;
if(someConditionIstrue)
{
Do some operations and calculate the value of i;
i = calculated value;
}

use i; //Note this value is only used not changed.
i = 10;// Compiler error

~Thanks

Daniel Krügler

unread,
Apr 3, 2013, 5:02:40 AM4/3/13
to std-dis...@isocpp.org
2013/4/3 smisra <shakti.mi...@gmail.com>

Hi,
I have seen in a lot of places code like

int i;
if(someConditionIstrue)
{
Do some operations and calculate the value of i;
i = some calculated value;
}

use i; //Note this value is only used not changed. It should not be changed.
But unfortunately in this case there is no way to guarantee it.
so now if some one comes and does

i = 10;// This is valid

What i was thinking: is there a way to tell that "i" can be set only once?

What is the value in your example, if "someConditionIstrue" evaluates to false?
 
After that it will be a constant. Something like

const once int i;
if(someConditionIstrue)
{
Do some operations and calculate the value of i;
i = calculated value;
}

use i; //Note this value is only used not changed.
i = 10;// Compiler error

But why don't you use the existing language tools here:

const int i = someConditionIstrue ? calculated value : other value;

At the moment I don't see much value in such a core language extension. The problem can be resolved with existing means.

- Daniel

smisra

unread,
Apr 3, 2013, 5:11:33 AM4/3/13
to std-dis...@isocpp.org
mostly
if(someConditionIstrue)
{
Do some operations and calculate the value of i;
i = calculated value;
}

May do a lot of things to calculate the value. Like read it from an xml for example. We can always create a function and do as you suggested. I am not telling about a feature to be added. Just asking if there is a cleaner way.

Ville Voutilainen

unread,
Apr 3, 2013, 5:39:54 AM4/3/13
to std-dis...@isocpp.org
One option would be a library wrapper that refuses setting the value
once its been set.
Such a latch type has been on my radar for at least boolean cases, in
order to provide
the same functionality people had for doing a ++flag for a bool. For
that idea I envisioned
just supporting bool and operator++, but it generalises to a set-once
facility, a bit like
once_flag but without the synchronization overhead.

Olaf van der Spek

unread,
Apr 3, 2013, 6:12:26 AM4/3/13
to std-dis...@isocpp.org
Op woensdag 3 april 2013 11:11:33 UTC+2 schreef smisra het volgende:
A lambda? 

Chris Jefferson

unread,
Apr 3, 2013, 1:53:05 PM4/3/13
to std-dis...@isocpp.org
This seems like the kind of thing attributes were designed for.
Unfortunatly, proving what happens in general could be very hard, what
if i gets passed by non-const reference to a method in another
translation unit? But with an attribute a compiler could take a "best
attempt" at warning.

Chris

Cassio Neri

unread,
Apr 3, 2013, 5:10:37 PM4/3/13
to std-dis...@isocpp.org

I wonder if a std::optional<const int>  (or, more generally, std::optional<const T> for any T) wouldn't be a solution for this problem. The semantics would be that a disengaged std::optional<const T> could be set to a T value but, once engaged, it couldn't be changed to another value (may be, even disengaging it wouldn't be allowed). If I understood it correctly, the current proposal doen't allow std::optional to be instantiated with const types. Anyway, I was just wondering...

Cheers,
Cassio.

Nicol Bolas

unread,
Apr 3, 2013, 8:27:15 PM4/3/13
to std-dis...@isocpp.org


On Wednesday, April 3, 2013 10:53:05 AM UTC-7, Chris Jefferson wrote:
On 03/04/13 09:21, smisra wrote:
> Hi,
> I have seen in a lot of places code like
>
> int i;
> if(someConditionIstrue)
> {
> Do some operations and calculate the value of i;
> i = some calculated value;
> }
>
> use i; //Note this value is only used not changed. It should not be
> changed.
> But unfortunately in this case there is no way to guarantee it.
> so now if some one comes and does
>
> i = 10;// This is valid
>
> What i was thinking: is there a way to tell that "i" can be set only once?
> After that it will be a constant. Something like
>
> const once int i;
> if(someConditionIstrue)
> {
> Do some operations and calculate the value of i;
> i = calculated value;
> }
>
> use i; //Note this value is only used not changed.
> i = 10;// Compiler error

This seems like the kind of thing attributes were designed for.

No it isn't. Attributes should not affect whether code is legal or illegal. Adding attributes to something should not be able to cause a compiler error.

Olaf van der Spek

unread,
Apr 4, 2013, 4:45:04 AM4/4/13
to std-dis...@isocpp.org
On Thu, Apr 4, 2013 at 2:27 AM, Nicol Bolas <jmck...@gmail.com> wrote:
> No it isn't. Attributes should not affect whether code is legal or illegal.
> Adding attributes to something should not be able to cause a compiler error.

Why not?
It's just like having warnings or considering warnings as errors.
--
Olaf

Ville Voutilainen

unread,
Apr 4, 2013, 4:47:04 AM4/4/13
to std-dis...@isocpp.org
Because attributes aren't supposed to have a semantic effect, and
changing whether
code is ill-formed is a semantic effect.

Olaf van der Spek

unread,
Apr 4, 2013, 4:58:00 AM4/4/13
to std-dis...@isocpp.org
But attributes would be allowed to emit a warning, right?
And users are allowed to turn warnings into errors?

--
Olaf

Daniel Krügler

unread,
Apr 4, 2013, 5:11:09 AM4/4/13
to std-dis...@isocpp.org
2013/4/4 Olaf van der Spek <olafv...@gmail.com>

This is all out of the scope of the C++ standard. In practice: yes

- Daniel

Ville Voutilainen

unread,
Apr 4, 2013, 6:20:44 AM4/4/13
to std-dis...@isocpp.org
On 4 April 2013 12:11, Daniel Krügler <daniel....@gmail.com> wrote:
>> But attributes would be allowed to emit a warning, right?
>> And users are allowed to turn warnings into errors?
> This is all out of the scope of the C++ standard. In practice: yes

An implementation is in general allowed to emit any diagnostics it pleases.
The standard doesn't forbid that, as far as I understand.

Daniel Krügler

unread,
Apr 4, 2013, 6:56:25 AM4/4/13
to std-dis...@isocpp.org
2013/4/4 Ville Voutilainen <ville.vo...@gmail.com>

Yes, sure. All I was trying to say is that the original two questions cannot be answered by consulting the C++ standard. And my reply part "In practice: yes" was intended to mean that existing compilers do allow to configure to turn warnings into errors and to emit any warnings they like.

- Daniel

Chris Jefferson

unread,
Apr 4, 2013, 2:56:08 PM4/4/13
to std-dis...@isocpp.org
True, but I still think attributes are for this kind of thing.

For example, the only standardised attribute is noreturn. [[noreturn]] functions can still return, but "Implementations are encouraged to issue a warning if a function marked [[noreturn]] might  return."

While an attribute might not be quite as good as a new language feature, an attribute would be (I suspect) much easier to implement and standardise, as it does not require new keywords, which are always a painful thing to introduce (certainly we couldn't introduce the keyword once. Perhaps there could be a context-sensitive keyword but that still introduces complexity, what if I had a type called once?)

Chris

Nicol Bolas

unread,
Apr 4, 2013, 9:07:54 PM4/4/13
to std-dis...@isocpp.org

No. If you want this feature, then you want a compiler error, just like you would have for non-const usage of a const variable. And if you want a compiler error, then you can't use an attribute. What is "easier to ... standardize" is irrelevant; if you want the feature, then you want the feature to be correct. What's the point of having a bad, poorly designed and implemented feature in the language?

Better to be slower and right than easier and wrong. Doing the latter leads to things like `export`.

Herb Sutter

unread,
Apr 5, 2013, 2:06:19 PM4/5/13
to std-dis...@isocpp.org
 
Bingo. Olaf nailed it: The way to do it is with a lambda. This is one of the examples I give in my talk Lambdas, Lambdas Everywhere (here are the slides from C++ & Beyond 2010).
 
In your example, do this:
 
const int i = [&]{
    int i = some_default_value;
    if(someConditionIstrue)
    {
        Do some operations and calculate the value of i;
        i = some calculated value;
    }
    return i;
} (); // note: () invokes the lambda!
 
That's the C++11 idiom for this. It's still being absorbed though -- not everyone knows about it yet as we're still all learning C++11 styles together.
 
Herb
 
 

chris.n....@gmail.com

unread,
Apr 5, 2013, 6:23:31 PM4/5/13
to std-dis...@isocpp.org
Shouldn't that lambda have an explicit return type? Even in a wider sense, any initialization complex enough to support using this idiom will use a lambda that doesn't qualify for an automatically-deduced return type. We might see full automatic return type deduction for lambdas in the future, though, so if that happens, I guess this correction will become moot.

Ville Voutilainen

unread,
Apr 5, 2013, 6:37:00 PM4/5/13
to std-dis...@isocpp.org
On 6 April 2013 01:23, <chris.n....@gmail.com> wrote:
Shouldn't that lambda have an explicit return type? Even in a wider sense, any initialization complex enough to support using this idiom will use a lambda that doesn't qualify for an automatically-deduced return type. We might see full automatic return type deduction for lambdas in the future, though, so if that happens, I guess this correction will become moot.

I have trouble understanding what part of the current return type deduction for lambdas isn't "full".

chris.n....@gmail.com

unread,
Apr 6, 2013, 3:51:02 AM4/6/13
to std-dis...@isocpp.org
From § 5.1.2/4 in the N3485 draft, it states the following, which disallows an automatically deduced return type other than void for any body other than return <expression>;:

If a lambda-expression does not include a trailing-return-type, it is as if the trailing-return-type denotes the following type:

— if the compound-statement is of the form
{ attribute-specifier-seqoptreturn expression ; }
the type of the returned expression after lvalue-to-rvalue conversion (4.1), array-to-pointer conversion (4.2), and function-to-pointer conversion (4.3);

— otherwise, void.

[Example:
auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = []{ return { 1, 2 }; }; // error: the return type is void (a
// braced-init-list is not an expression)
— end example ]

Ville Voutilainen

unread,
Apr 6, 2013, 5:22:33 AM4/6/13
to std-dis...@isocpp.org
On 6 April 2013 10:51, <chris.n....@gmail.com> wrote:
From § 5.1.2/4 in the N3485 draft, it states the following, which disallows an automatically deduced return type other than void for any body other than return <expression>;:

chris.n....@gmail.com

unread,
Apr 6, 2013, 5:28:13 AM4/6/13
to std-dis...@isocpp.org
I agree. I'm not quite sure why the limitations were set in the first place. There's a similar fix in the return type deduction proposal, which uses the proposal as leverage for lambda return types as well.

Ville Voutilainen

unread,
Apr 6, 2013, 6:10:54 AM4/6/13
to std-dis...@isocpp.org
On 6 April 2013 12:28, <chris.n....@gmail.com> wrote:
I agree. I'm not quite sure why the limitations were set in the first place. There's a similar fix in the return type deduction proposal, which uses the proposal as leverage for lambda return types as well.

Yes, and that one is proceeding to the CWG with the blessing of the EWG, so we need to put Core 975 into the same train.

mordac...@gmail.com

unread,
Apr 8, 2013, 9:19:47 AM4/8/13
to std-dis...@isocpp.org
Personally, I have always wished that { } compound-expressions could reduce to a value, without having to create a function for them.

Then you could use:

const int i = condition ? { compound-expression-resulting-in-int } : 0;



With lambdas, you can get what you want with:

auto compute_i =  [&] () { compound-expression-returning-int };
const int = condition ? compute_i() : 0;


Like you - I find this sort of code to be an annoying distraction because the need occurs often, and the language offers a bit of a kludge for an answer (due to inability to use braced-expressions-that-evaluate-to-a-value everywhere).  But that's obviously just my opinion. :)
Reply all
Reply to author
Forward
0 new messages