More Flexible "final"

C

Christian

Hello

I have been wondering why the final keyword for instance variables is
not more flexible.
Often in my code I find situation when it would have been
helpful/produced nicer code if I were able to change a final variable
while being in the constructor .

Is there any reason behind it that we can't change a final variable
multiple times while we are in the constructor?

It would be interesting to know why it is like it is in java.
What benefit does java get by not allowing this?

Christian
 
S

Stefan Ram

Christian said:
Often in my code I find situation when it would have been
helpful/produced nicer code if I were able to change a final
variable while being in the constructor .

If this happens so often, then it
should be easy to post an example.
 
C

Christian

Stefan said:
If this happens so often, then it
should be easy to post an example.

here an example for my last recent occurence..

/**
* decorates a normal NC Block that is a TreeCoding Block
*/
public TreeCodingBlock(INCBlock block, TreeCodingBlockmanager manager) {
this.decorated = block;
this.manager = manager;
int firstPositionUnequalZero = 0;
int lastPositionUnequalZero = 0 ;
ByteVector linearfactors = block.getLinearFactors();

for (int i=0; i < linearfactors.length(); i++) {
if (linearfactors.getElement(i) != 0) {
firstPositionUnequalZero = i;
break;
}
}
for (int i = linearfactors.length()-1 ; i >= 0 ; i-- ) {
if (linearfactors.getElement(i) != 0) {
lastPositionUnequalZero = i;
break;
}
}
this.firstPositionUnequalZero = firstPositionUnequalZero;
this.lastPositionUnequalZero = lastPositionUnequalZero;
}

Well I can remember worse examples.. here it adds just four lines of
code. Though four lines that seem unecessary.
 
E

Eric Sosman

Christian said:
Hello

I have been wondering why the final keyword for instance variables is
not more flexible.
Often in my code I find situation when it would have been
helpful/produced nicer code if I were able to change a final variable
while being in the constructor .

Is there any reason behind it that we can't change a final variable
multiple times while we are in the constructor?

The only scenario I can think of where a `semifinal' might
help is when there are multiple constructors, and one of them
chains to another before setting the variable:

private Something instanceVariable;

public SomeClass() {
doLotsOfStuff();
instanceVariable = new Something(42);
}

public SomeClass(int value) {
this();
instanceVariable = new Something(value);
}

The obvious answer in this case is to rearrange responsibilities:

private Something instanceVariable;

public SomeClass() {
this(42);
}

public SomeClass(int value) {
doLotsOfStuff();
instanceVariable = new Something(value);
}

Or perhaps you're worried about running a loop that might
set the variable several times, as in:

private Something instanceVariable();

public SomeClass(Collection<Something> things) {
for (Something thing : things)
if (thing.somePredicate())
instanceVariable = thing;
}

This is easily fixed by introducing a local variable:

private Something instanceVariable;

public SomeClass(Collection<Something> things) {
Something chosen = null;
for (Something thing : things)
if (thing.somePredicate())
chosen = thing;
instanceVariable = chosen;
}

If you have some other situation that seems to cry out for
a `semifinal' variable, please post it.
It would be interesting to know why it is like it is in java.
What benefit does java get by not allowing this?

Simplicity: If the rules are easy to state ("one and only
one assignment") things are easier for both the compiler and
for the human reader. Error detection: Did the programmer truly
intend to make multiple assignments, or did some execution path
escape his notice? Maybe other reasons, too.

Let's turn the question around: What benefit would accrue
from *allowing* `semifinal' variables?
 
S

Stefan Ram

Christian said:
for (int i=0; i < linearfactors.length(); i++) {
if (linearfactors.getElement(i) != 0) {
firstPositionUnequalZero = i;

This breaks Demeter's Law, because it addresses an object
»linearfactors« obtained from a parameter object (»block«).

It also breaks the GRASP information expert pattern: »block«
has the information to calculate »firstPositionUnequalZero«,
so it should implement this operation.

Thus (simplified):

public TreeCodingBlock
( final INCBlock block )
{ this.firstPositionUnequalZero = block.firstPositionUnequalZero();
this.lastPositionUnequalZero = block.lastPositionUnequalZero(); }
 
D

Daniel Pitts

Christian said:
here an example for my last recent occurence..

/**
* decorates a normal NC Block that is a TreeCoding Block
*/
public TreeCodingBlock(INCBlock block, TreeCodingBlockmanager manager) {
this.decorated = block;
this.manager = manager;
int firstPositionUnequalZero = 0;
int lastPositionUnequalZero = 0 ;
ByteVector linearfactors = block.getLinearFactors();

for (int i=0; i < linearfactors.length(); i++) {
if (linearfactors.getElement(i) != 0) {
firstPositionUnequalZero = i;
break;
}
}
for (int i = linearfactors.length()-1 ; i >= 0 ; i-- ) {
if (linearfactors.getElement(i) != 0) {
lastPositionUnequalZero = i;
break;
}
}
this.firstPositionUnequalZero = firstPositionUnequalZero;
this.lastPositionUnequalZero = lastPositionUnequalZero;
}

Well I can remember worse examples.. here it adds just four lines of
code. Though four lines that seem unecessary.
Try refactoring to replace temp with query:
private static int findFirstNonZeroPosition(ByteVector bv);
private static int findLastNonZeroPosition(ByteVector bv);

Actually, better yet, add those methods as instance methods to
ByteVector if possible.
 
C

Christian

Stefan said:
This breaks Demeter's Law, because it addresses an object
»linearfactors« obtained from a parameter object (»block«).

It also breaks the GRASP information expert pattern: »block«
has the information to calculate »firstPositionUnequalZero«,
so it should implement this operation.

Thus (simplified):

public TreeCodingBlock
( final INCBlock block )
{ this.firstPositionUnequalZero = block.firstPositionUnequalZero();
this.lastPositionUnequalZero = block.lastPositionUnequalZero(); }

for INCBlock interface the first position unequal to zero has no meaning...
therefore it was not implemented in INCBlock , also ByteVector had no
need for such a method

TreeCodingBlock is in a plug-in that provides a "Blockmanager" a class
that may decorate any INCBlocks .. this decorater now has some use to
have a fast way to know whats the first factor unequal to zero is ..

though I will follow Daniel Pits advice and add it to the ByteVector's
methods as it is not really a problem to change to original program..

thx
 
R

Roedy Green

Is there any reason behind it that we can't change a final variable
multiple times while we are in the constructor?

because final means FINAL, not to be changed again. If you need to do
some temporary calculation before coming up with the value, put the
temps is a local variables, then mark the result final.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top