Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a real constant keyword and rename the current behaviour #992

Closed
axic opened this issue Sep 1, 2016 · 47 comments
Closed

Introduce a real constant keyword and rename the current behaviour #992

axic opened this issue Sep 1, 2016 · 47 comments

Comments

@axic
Copy link
Member

axic commented Sep 1, 2016

I think the following makes more sense compared to what we have now.

Now:

  • constant function should not modify the state (not fully enforced yet)
  • constant state variable (ie. the one in the class and not in a method) is evaluated every time it is called

After the change:

    1. the keyword view is introduced for functions (it replaces constant). Calling a view cannot alter the behaviour of future interactions with any contract. This means such functions cannot use SSTORE, cannot send or receive ether and can only call other view or pure functions.
    1. the keyword pure is introduced for functions, they are view functions with the additional restriction that their value only depends on the function arguments. This means they cannot use SSTORE, SLOAD, cannot send or receive ether, cannot use msg or block and can only call other pure functions.
    1. the keyword constant is invalid on functions
    1. the keyword constant on any variable means it cannot be modified (and could be placed into memory or bytecode by the optimiser)
  • 5) the keyword volatile is introduced for variables, which read their referenced value every time (this is what constant does today to variables) [agreed to remove this functionality]

Any example of the volatile keyword:

contract A {
    uint volatile number = block.number;
    function a() returns (uint) {
        return number; // this returns the *current* block.number every time it is called
    }
}

I'm not sure the volatile option is useful and thus we might decide to remove it.

@axic axic changed the title Rename the current constant keyword (and reserve it for the future) Introduce a real constant keyword and rename the current behaviour Sep 1, 2016
@Arachnid
Copy link

Arachnid commented Sep 1, 2016

the keyword stateless is introduced for functions (it replaces constant)

This seems like the wrong word; constant functions are definitely not stateless; they often depend on state. If a new name must be used, perhaps something like immutable or pure (in the sense that a pure function is side-effect-free, which is what we're really describing)?

@axic
Copy link
Member Author

axic commented Sep 1, 2016

I'm trying to find the word and stateless ia far from perfect. It should describe that the state is not modified.

Also additionally we could introduce real constant functions, which are indeed stateless and dont depend on the state. I.e. calculating something based on the inputs.

@Arachnid
Copy link

Arachnid commented Sep 1, 2016

Well, from a CS-theoretic POV, 'pure' is definitely the term you want. More informally, 'side effect free', but that's harder to condense into a keyword.

@redsquirrel
Copy link
Contributor

I think 'immutable' will be the least ambiguous to most developers.

@axic
Copy link
Member Author

axic commented Sep 1, 2016

I like pure, but are we likely to find another use for it? Does view as keyword make sense?

@axic
Copy link
Member Author

axic commented Sep 1, 2016

@redsquirrel immutable wouldmean to me that child classes cannot ovveride it.

@redsquirrel
Copy link
Contributor

@axic I suggest following Java and using 'final' for functions that cannot be overridden.

@Arachnid
Copy link

Arachnid commented Sep 1, 2016

I like pure, but are we likely to find another use for it?

I don't think so; certainly this is the only usage for the term I'm aware of.

I suggest following Java and using 'final' for functions that cannot be overridden.

I don't think that was under discussion here?

@VoR0220
Copy link
Member

VoR0220 commented Sep 1, 2016

I agree that we should use pure...perhaps strict? But I really like the idea of pure as a side effect free input. Rather than volatile which conjures up bad imagery, why not static?

@chriseth
Copy link
Contributor

chriseth commented Sep 1, 2016

nonmutating?

@VoR0220
Copy link
Member

VoR0220 commented Sep 1, 2016

too long...overly blunt descriptive. Less is more imo.

@ethernomad
Copy link
Contributor

readonly?

@VoR0220
Copy link
Member

VoR0220 commented Sep 1, 2016

what's wrong with pure or strict as is used in js?

@axic
Copy link
Member Author

axic commented Sep 1, 2016

Many of the definitions of pure say it does not depend on state and no matter when it is called, based on the input parameters it should always return the same predictable result.

Therefore it does not suit our application.

@VoR0220 static does not reflect what it is. The volatile part is a different behaviour (= what constant variables do).

Updated the description with further clarification which should help coming up with a good name.

@VoR0220
Copy link
Member

VoR0220 commented Sep 1, 2016

hmmm...so I like that idea in regards to pure it enables solidity to become "functional" (and pleases all the zealots), but in regards to view...I think it might be better to just bite the bullet and call it immutable (because that's what it is). As for volatile, there are uses for it, but not many...probably just call it mutable.

@chriseth
Copy link
Contributor

chriseth commented Sep 1, 2016

The problem with immutable is that you cannot apply that adjective to the function. The function itself never changes.

@VoR0220
Copy link
Member

VoR0220 commented Sep 1, 2016

right but the output does. Perhaps you could create such a differentiation. You might do something like this

function f) returns immutable (my, output, signature) {

}

@axic
Copy link
Member Author

axic commented Sep 1, 2016

@VoR0220 it is not the output or the function which is mutable/immutable.

Case 1: function can read state variables (sload). The output of this function will depend on the current state.

Case 2: function can modify state variables (sstore). The output of this function will depend on the current state, as well as it can change the state, which then affects any future invocations.

I've borrowed view from databases. The function provides a modifiedview of the current state (i.e. it uses sload and applies transformations).

@axic
Copy link
Member Author

axic commented Sep 2, 2016

Can we agree that the behaviour called volatile above should not be present and we can remove it?

@ethers
Copy link
Member

ethers commented Sep 2, 2016

I don't see much need for volatile.

Many of the definitions of pure say it does not depend on state and no matter when it is called, based on the input parameters it should always return the same predictable result.
Therefore it does not suit our application.

Doesn't the current proposal fit pure? 2) the keyword pure is introduced for functions (they cannot call SSTORE or SLOAD)
Which part is pure breaking?

I think the 4 proposals are good. No one else has made comments about readonly, and I think it fits well with in the 1st proposal, which would read as:

  1. the keyword readonly is introduced for functions (it replaces constant, these functions cannot call SSTORE, but can call SLOAD)

readonly and pure sound accurate enough.

@axic
Copy link
Member Author

axic commented Sep 2, 2016

Doesn't the current proposal fit pure?

Sorry for the confusion, the description was updated after those comments. pure (and every other keyword) was initially proposed for what 1) is. It fits 2) well.

For 1) I like view, readonly, and nonmutating (but this is way too long).

@Arachnid
Copy link

Arachnid commented Sep 2, 2016

Many of the definitions of pure say it does not depend on state and no matter when it is called, based on the input parameters it should always return the same predictable result.

Yes, you're right - I stand corrected. readonly is probably the sanest I've seen so far, though view also works.

RE constant/volatile/etc, besides dropping the functionality (which seems good to me), why not call it 'alias' or 'define'? That seems to be effectively what it is.

@chriseth
Copy link
Contributor

chriseth commented Sep 2, 2016

I think that volatile is just a buggy behaviour of constant. We can introduce something like alias in the future, it is certainly planned for types (using x = y) and could also be introduced for general expressions.

I updated the description to specify the behaviour in more detail.

Question: Can a pure function return address(this)? I.e. is it required to be pure just from its source code or is it fine to be pure "after deployment"? Can a pure function return a storage value that it set in the constructor (i.e. from the block hash) and never modified in the contract?

From the keywords: The problem with readonly is similar to the one with immutable - it applies to the function while it should apply to the state. On the other hand, view is not an adjective.

@axic
Copy link
Member Author

axic commented Sep 6, 2016

@chriseth moved alias into its own issue and removed volatile from the description.

I.e. is it required to be pure just from its source code or is it fine to be pure "after deployment"?

That is a good question. I would argue that it is more useful to allow this and any constants set during the constructor (if that becomes possible).

Storage should not be accessed by pure functions unless we introduce writeonce storage slots set during the constructor, but what is the reason to use them? They are more expensive than storing it in bytecode.

@chriseth
Copy link
Contributor

chriseth commented Jan 2, 2017

I think we more or less found that our framework is not yet fully specified because pure functions might modify memory. My current proposal would be the following:

view and pure are attributes applied to the function, and they only concern storage and other permanent state.
The pure keyword should be renamed, because a "pure" function is still able to modify memory references that are passed in (but not storage references). In order to prevent this, the type of such an input variable has to be <memory type> constant.

So in essence, "view" and "pure" apply to "this" (and other state including other contracts) and all other input variables have their own specifiers.

@3esmit
Copy link
Contributor

3esmit commented Mar 3, 2017

I suggest the new name as expression or volatile that will evaluate in each call.
See this code:

contract LockableCoin is AbstractCoin {
    //creation time, defined when contract is created
    uint public creationTime = now;
    //time constants, defines epoch size and periods
    uint public constant UNLOCKED_TIME = 25 days;
    uint public constant LOCKED_TIME = 5 days;
    uint public constant EPOCH_LENGTH = UNLOCKED_TIME + LOCKED_TIME;
    //current epoch constant formula, recalculated in any contract call
    uint public constant CURRENT_EPOCH = (now - creationTime) / EPOCH_LENGTH + 1;    
    //next lock constant formula, recalculated in any contract call
    uint public constant NEXT_LOCK = (creationTime + CURRENT_EPOCH * UNLOCKED_TIME) + (CURRENT_EPOCH - 1) * LOCKED_TIME;
//(...)
}

From https://github.com/ethereans/github-token/blob/master/contracts/LockableCoin.sol

@3esmit
Copy link
Contributor

3esmit commented Mar 24, 2017

Why word volatile being not considered? I see use cases for this, and its really useful and easy to understand. Volatile are expressions that result a value change due contract storage, chain or call variables change.
Such as:

 //caller balance
    mapping (address => uint) balances;
    uint volatile callerBalance = balances[msg.sender];

//lock epoch
    uint256 public creationTime = now;
    uint256 public unlockedTime = 25 days 
    uint256 public lockedTime = 5 days; 
    uint256 public volatile EPOCH_LENGTH = unlockedTime + lockedTime;
    uint256 public volatile CURRENT_EPOCH = (now - creationTime) / EPOCH_LENGTH + 1;    
    uint256 public volatile NEXT_LOCK = (creationTime + CURRENT_EPOCH * unlockedTime) + (CURRENT_EPOCH - 1) * lockedTime;

I was first fooled by a constant owner that changed in any call, but using a special keyword for this case makes sense.
Just removing this hability makes solidity more restrictive.
Volatile is useful when you need a constant that is synced to various variables and is used a lot of times in almost all functions, if not this case, internal function and a memory var is better.

@chriseth
Copy link
Contributor

I like to restrict the number of keywords as much as possible, especially if there is another solution that does almost the same thing.

@pirapira
Copy link
Member

Related: #2181

@axic
Copy link
Member Author

axic commented Aug 15, 2017

Here is a summary of the current design:

There's enum for statemutability, from most restricted to least restricted: pure, view, nonpayable, payable. A function can only be one of these.

view:

  • cannot use selfdestruct, new
  • can use this.balance
  • can use tx.*, msg.*, block.*
  • can only call view or pure functions
  • cannot send ether
  • can use sload
  • cannot use sstore

pure:

  • cannot use selfdestruct, new, log, this.balance, address.balance, tx.*, msg.*, block.*
  • can only call pure functions
  • cannot use sload
  • cannot use sstore

Remarks:

  • JSON ABI has a new field statemutability introduced with a string value as above
  • JSON ABI keeps constant/payable for backwards compatibility for a while
  • constructor / fallback cannot be view or pure
  • constant as a specifier on functions is phased out (removed at the next breaking release)

@axic
Copy link
Member Author

axic commented Aug 25, 2017

This is finally implemented and documented. To only thing left is enforcing these restrictions and that is tracked in #2606.

@fulldecent
Copy link
Contributor

What version is this implemented in?

@bitsnaps
Copy link

bitsnaps commented Mar 6, 2018

@fulldecent I believe view and constant are both working right now, I would like to see readonly, but for compatibility I prefer to stick with view, it's still less ambiguous than constant anyway
https://ethereum.stackexchange.com/questions/25200/solidity-what-is-the-difference-between-view-and-constant

@mojl
Copy link

mojl commented Mar 7, 2018

Is it normal behavior for a pure function to access a constant "state variable"?

It make sense architecture-wise, but is this intended and will be doubled down on?

@axic
Copy link
Member Author

axic commented Mar 7, 2018

A constant "state variable" is just a constant value, it is not a storage variable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests