A need for const?

Now I may be totally off the mark here, so maybe people can put me straight…

Imagine the handy little class ‘Vector2f’, just a simple little math class. Now in C++ I’d happily write:

const Vector2f getPosition();

to get an objects position, safe in the knowledge that who ever is calling the method can’t tinker with the returned object. All well and good. But the Java equivilent would be without any sort of ‘const’ modifier, and so open up the class to be modified in an unintended way, bypassing the intended set method.

‘final’ to the best of my knowledge, just makes the reference final, not the actual data, and is therefore not a substiture. So the alternative would be

void getPosition(Vector2f dest);

and having a blank object into which the new information is copied. That or return a copy, but both of these need an extra object to be created just to hold what will likely be a temporary result.

Now I may be being overly paranoid about the GC, but this is getting to be really annoying. I don’t like possibly creating hundreds of tiny little objects per frame, and the alternative of keeping them around (or a small number of temporary ones around and reusing them) gets ugly when used to any large extent.

If the Vector2f class is yours you may want to consider creating an immutable version of it. Something like:


public interface Vector2f {
    public float getX();
    public float getY();
    // other methods
}

public class ImmutableVector2f implements Vector2f {

    private final float x;
    private final float y;
    public ImmutableVector2f(float x, float y) {
    this.x = x;
    this.y = y;
    }

    public float getX() {
    return x;
    }

    public float getY() {
    return y;
    }
}

public class MutableVector2f implements Vector2f {
    private float x;
    private float y;
    public MutableVector2f(float x, float y) {
    this.x = x;
    this.y = y;
    }

    public float getX() {
    return x;
    }

    public float getY() {
    return y;
    }
    
    public void setX(float x) {
    this.x = x;
    }

    public void setY(float y) {
    this.y = y;
    }
}

It’s not quite the same as const, but it gets you at least part of the way there.

Oops. disregard my last missive. I misread your post :slight_smile:

There are little tricks you can do.


public class Vector2F
{
      int getX() { ... }
      int getY() { .. }
}

public class MutableVector2F extends Vector2F
{
      void setX(int x) { ... }
      void setY(int y) { ... }
}

public class MyClass
{
      private MutableVector2F myVector;
      
      public Vector2F getPosition()
      {
            return myVector;
      }
}

You’re returning your vector truncated as the immutable base class. Only you can (honestly) alter it. You could take it one step further and make MutableVector2F a private class of your class.

That offers the same protection as C++ does, generally. It prevents honest use of your class from accidentally damaging things. Dishonest use is possible, sure, just cast it down to the mutable form. But that’s deliberate, and if you’re own code is doing that, then something else is wrong. If someone else is deliberately trying to mess up your vector, then C++ offers you the same shakey safety, casting away constness is very easy.

Incidentally a lot of Swing classes take it to the extreme and return a copy of the object. Ugh.

Since we’re on the subject of tricks you could make your an inner class with private member variables, which would only be accessible to the outer class, like so:


public class Vector2F {
  public float getX() { ... }
  public float getY() { .. }
} 

public class MyClass {

private MyVector2f position = new MyVector2f();

public void setPosition(float x, float y) {
        position.x = x;
        poxition.y = y;
}

public Vector2f getPosition() {
        return position;
}

private static class MyVector2f extends Vector2f {
        private float x;
        private float y;
        public float getX() { return x; }
        public float getY() { return y; }
}
}


Unlike the previous example, the Vector2f returned from getPosition() can’t be cast into a mutable form, but thanks to scoping your outer class can modify it. This of course assumes that Vector2f isn’t final or contains so many methods that overriding it this way is a pain in the @ss. It does however do what you want it to, namely prevent someone else from modify the object while giving your class the ability to, if in a somewhat convoluted way.

All this is besides the point that (C++ style) const would be damn useful. I’ve often wonder why Java didn’t pick it up from C++ on the way…

Does anyone know why?

Kev

Thats quite a neat trick, I’ll probably use that at some point, but in this actual case there are a lot of methods and to have to do this everywhere needed would be a large amount of work for not enough gain :-/

Would be nice to get a proper ‘const’, but I guess most people think that returning a copy is an acceptable solution :-[

Nah, returning a copy is a sucky solution :frowning: Const is a handy keyword which is really a shortcut for creating tons of irritating get methods and read-only interfaces.

I like programming shortcuts. Every byte I type is a byte that can go wrong :confused:

Cas :slight_smile:

Const was left out because it was deemed unnecessary, and a complication. Much like unsigned, enum, generics, multiple inheritance and all the other interesting stuff people still clamour to add!

Vote here:

http://developer.java.sun.com/developer/bugParade/bugs/4211070.html

const is nice, but it does complicate things. I think Sun just wanted to keep Java slim and straightforward. Although I do think the omission of unsigned was a complete sin :slight_smile:

[quote]Much like unsigned, enum, generics, multiple inheritance and all the other interesting stuff people still clamour to add!
[/quote]
Well, at least enums and generics will finally be showing up in 1.5. And const has been set aside as a keyword in Java, so… who knows?

That said, I wouldn’t hold my breath waiting for multiple inheritence. :slight_smile:

No, agreed! Multiple inheritance causes more problems than it’s worth (although I can come up with persuasive reasons to have it). Operator overloading is another thing I’m glad to see the back of, after a fashion!

Unsigned really used to annoy me - I mean, what’s an unsigned byte? That just doesn’t make any sense! You get used to it after a while though. ::slight_smile:

[quote]Thats quite a neat trick, I’ll probably use that at some point, but in this actual case there are a lot of methods and to have to do this everywhere needed would be a large amount of work for not enough gain :-/
[/quote]
Ooh, wait… Here’s another flavor of the solutions:


public class Vector2F {
 public float getX() { ... }
 public float getY() { .. }
 public void setX(float x) throws ImmutableException { ... } 
 public void setY(float y) throws ImmutableException { ... }

 // bunch o' other methods
}  
 
public class MyClass {
 
 private MyVector2f position = new MyVector2f();
 
 public void setPosition(float x, float y) {
  position.secretSetX(x);
  poxition.secretSetY(y);
 }
 
 public Vector2f getPosition() {
  return position;
 }
 
 private static class MyVector2f extends Vector2f {
  public void setX(float x) 
   throw new ImmutableException();
  }
  public void setY(float y) 
   throw new ImmutableException();
  }
  private void secretSetX(float x) {
   try {
    super.setX(x);
   } catch(ImmutableException e) { // do nothing } 
  }
  private void secretSetY(float y) {
   try {
    super.setY(y);
   } catch(ImmutableException e) { // do nothing } 
  }
 }
}  

Same result as previous solution, but all you have to do is reimplement your “set” methods.

You can also make the MyVector2f and the “secret” methods package local, in which case you’d only have to implement MyVector2f once per package that was going to use it.

I’m a stong believer in scoping classes to the scope of their use. If a class is only used within another class, I make it an inner class. If it’s only used by other classes in a given package, I make it package local, etc, etc But that’s another debate altogether.

Yes, but then again… so it goto… :o

[quote]Operator overloading is another thing I’m glad to see the back of, after a fashion!
[/quote]

String whatAbout = "String " + "concanenation?";

except your setX() never actually sets anything, it just throws the exception. So your secretSetX() won’t actually set anything either.

Personally, I think the existance of the “Immutable” design pattern and the need for convoluted solutions like those detailed above, should be argument enough for adding const, but that’s just me. I’m sure there are a host of reasons, technical and otherwise, for it’s exclusion, but it certainly would be nice.

[quote]except your setX() never actually sets anything, it just throws the exception. So your secretSetX() won’t actually set anything either.
[/quote]
secretSetX() (in MyVector2f) calls super.setX() (setX() in Vector2f) which presumably has some code to replace the “…” shorthand to actually set the value of X.

One of the biggest reasons for having const is passing arguments by const reference. Without pass by reference in Java, const loses a lot of use.

Even Orangy Tang’s example is usually not done quite that way in C++, usually a const reference is returned.

Ah yup, just being stupid. Too early in the morning for me :slight_smile:

[quote]One of the biggest reasons for having const is passing arguments by const reference. Without pass by reference in Java, const loses a lot of use.
[/quote]
Deftly stepping around the whole ‘Java passes everything by value’ argument, how is the C++ code:
void Class::SomeFunc(Vector2f* position);
any different from Java:
void someFunc(Vector2f position);
? This is another area that i feel like const would be handy - I don’t want to pass in the actual object because i don’t want it changed, yet making a copy is a waste of time. A simple const modifier is exaxtly whats needed (could this be a compile time check, and thus be added to the language without too much fuss?). Instead of the nice simple
void someFunc(const Vector2f position);
I end up with the rather more ugly:
void someFunc(float x, float y);

[quote]Even Orangy Tang’s example is usually not done quite that way in C++, usually a const reference is returned.
[/quote]
Well really its not what i usually come across in C++ code, its usually something like
void Class:GetPos(Vector2f* pos);
which is nice because the caller can just create the object on the stack and let it quietly go out of scope without worrying about a GC sticking its neak in…

Edit: its not a simple compile time modification, you can’t tell if a given method will modify the object or not until runtime.

Generally they’re not that different. In both cases you’re passing in a copy of the pointer/reference to the object. Since it’s a new copy, you can’t cause the original pointer/reference to refer to a new object.

But that’s a C++ pointer, not reference.

with

void foo(SomeObject &bar);

you’ve passed in the actual object via reference. This method has free reign on this object, including causing it to be an entirely new object altogether. Sometimes you want that sometimes you don’t.

void foo(const SomeObject &bar);

Same thing, but bar can’t be altered in anyway. No expensive copying, you get the object to work with and it’s safe. Everyone’s happy.

This is essential when templates come into play

template
void foo(const T &bar);

that T could be a lowly byte to a gigantic object. Since you don’t know, you really don’t want to copy it, const reference passing becomes crucial.

And of course, being C++, there’s about a billion other combinations, const pointers, pointer references, pointers to pointers, on and on.

Why though? just do

const Vector2f &getPos() const;

no object creation takes place at all, and everyone gets a loot at the object in a safe way.