# Proposal: Remove Lifetime Methods¶

Note

Feature awaiting further design consideration.

This is a proposal to remove lifetime methods and eliminate the concept of an object having a ‘dead’ state.

## Rationale¶

Lifetime methods add significant complexity to the language, and the dead state is particularly something that has to be defined carefully.

Due to the inner/outer separation, method calls to __move and __destroy don’t have any effect in the dead state.

## Changes¶

This proposal aims to remove lifetime methods by ensuring that all accessible objects are always in a live state.

### Move¶

Currently it’s possible to create a dead state by moving out of a variable:

void f(Object value) {
g(move value);
// 'value' now in 'dead' state.
}


This usage of move is reasonable and useful; this proposal therefore suggests that value cannot be accessed after a move operation:

void f(Object value) {
g(move value);

// ERROR: cannot access variable 'value' after move.
value.method();
}


move can also be used on arbitrary reference-typed values:

void method() {
f(move @memberVariable);
}

This proposal suggests to make such usage illegal; move can only be used on local variables (instead mechanisms a swap() function could be used).

Ultimately it would be ideal to be able to use move on all references, followed by some kind of re-assignment. For example, the following is very likely safe:

void method() {
f(move @memberVariable);
new(&@memberVariable) Object();
}

So future work would allow the compiler to prove this is safe.

### Assignment¶

The status of assignment is currently unclear; this proposal clarifies it by defining it as a normal method of a class:

class Object {
void assign(Object value) noexcept;
}


Importantly this means variables cannot be assigned after they have been moved. A new operator might be used for this case:

void f(Object value) {
g(move value);
value := Object();
}


An alternative is to keep using placement new:

void f(Object value) {
g(move value);
new(&value) Object();
}


### Destructor¶

Destructors would no longer implicitly check for the dead state, since they would be guaranteed to only be run once for each object.

These are no longer needed and can be removed.

### Containers¶

Due to the changes containers must now provide a way to extract elements; their erasing methods would return the element being removed. For example, std::varray<T>::pop_back() would now return a T.

### Ranges¶

The existing ranges still work, but there may need to be new range types (which could be called ‘generators’) that support extracting elements:

template <typename T>
interface input_generator {
bool empty() const;
T pop_front();
}

template <typename T>
interface bidirectional_generator {
bool empty() const;
T pop_front();
T pop_back();
}


These interfaces match the containers themselves. As part of these changes, output_range could become output_generator:

template <typename T>
interface output_generator {
void push_back(T value);
}