First off, it's important to know the difference between value types and objects.
For a value type, public final fields are good. They are set in the constructor once, and can only be read, and can't change. Getters are pointless, and my code does not have them. If you want them for a reason, then intellij does an amazing job fixing that.
Objects encapsulate mutable state, and getFoo() and setFoo() are inappropriate methods to have. They should be things that affect the behavior of the object, not simple setters and getters.
The big issue is that a lot of java was created when we still hadn't figured out how to properly do Object Oriented Programming. But we know now (well - some of us), and there is nothing in Java that prevents you from doing it well.
Contrast Java with Ruby or C#. There, the clients don't need to know whether they're accessing a member var or calling a method to get/set a property, NOR SHOULD THEY. The inability to do this in Java fundamentally breaks encapsulation.
Others have noted that in many contexts in C# there is a difference, so clients do need to know.
As far as Ruby, clients definitely need to know, its just that since public fields can't happen in Ruby, its always method-based access for the normal cases.
Both of these lines are always calling a method on "obj" in Ruby:
foo = obj.a # equivalent to foo = obj.a()
obj.a = foo # equivalent to obj.a=(foo)
While these are using instance var (the closest thing to a "field" in Ruby) access: foo = obj.instance_variable_get :@a
obj.instance_variable_set :@a, foo
foo = obj.instance_eval { @a }
obj.instance_exec { @a = foo }
There's no common syntax like C#-style properties that unifies field-based and method-based access, so Ruby is sort of the extreme opposite of attempts to have "properties" that make method-based access look the same as field-based access in the same language, even though its method syntax can make method-based access in Ruby look like field-based access in a completely different language.Which is why C# added automatic properties. You get the expandability without breaking clients or having to read/write extra code.
public int Foo { get; set; } public int Foo { get; private set; } public string Foo { get { return ""; } }
private void DoBar(ref string input) { input = "123"; }
public void Main() { DoBar(ref Foo); }
Typically C# points you towards using a different methodology than ref/out parameters. But I do agree it is annoying when you want to use them. class Foo(object):
def __init__(self, bar):
self._bar = bar
@property
def bar(self):
return self._bar
@bar.setter
def bar(self, value):
self._bar = valueSure, you can beat the big ones into working, and there is generally no shortage of libraries in Java. But at some point you are just wasting resource to work around other people code. Java has properties and some libraries use them.
Discussing if you should use them at all is offtopic, the real problem is that java has properties but instead of being a language/compiler supported feature, it is only defined as a "convention" with some half-assed support classes. Seeing how popular properties are, that either needs fixing or deprecation (starting with all the Oracle provided framework that use them)
This! A lot of the horrible Java you see around is nothing but an artifact of mindlessly applying patterns to constructs that don't need them.
> a lot of java was created when we still hadn't figured out how to properly do Object Oriented Programming.
Which is quite unforgivable, considering Smalltalk has been around since the early 80's.
Let's see. OOP generally involves "objects", ie structs or records with visibility controls on fields, sporting "methods," ie functions with a magic/hidden this/self argument. This alone doesn't buy you much, and in fact is quite inflexible when compared to good old ADTs, so let's hope there's more to it.
OOP does not mean "all methods are defined within the class declaration/file" a la Java, plenty of OOPLs allow external method definition. So it doesn't mean "well in OOP I always know the behavior of my class" when you have friend functions etc.
OOP might mean "abstract classes" ie virtual methods. This leads us to inheritance, which is a) not confined to OOP and b) widely criticized. Remember that inheritance != polymorphism, c.f. Visual Basic for instance (at least VB5. Showing my age...). In practice, OOP usually invokes a great-chain-of-being-like hierarchy descending from Object, but again this is not universal.
OOP generally means "polymorphism", but the mechanisms vary widely. OOP's "Classic" inheritance-driven polymorphism is probably the worst way to do it, good for quick code-reuse and that's about it. "Interfaces"/pure virtual classes are a design pattern on top of abstract classes, better expressed as mixins or type-classes.
OOP generally implies strong typing but not always (python). OOP typing is quite clunky, especially in "noun-oriented" Java. You can make an argument that the rise of DI frameworks is in response to having impoverished type systems.
My semi-rant here is because people say things like "do it this way, it's good OOP" without there being any agreement about whether we're discussing polymorphism, inheritance, encapsulation, factoring, normalization, or design patterns that are largely a response to the confusion.
On the other hand we have folks like the clojure crowd bagging on OOP using similarly vague concepts like "OOP means stateful objects/side effects" ...
It at least buys you a way of organizing your code that makes it easier to understand not just for yourself, but other programmers who read it in the future. Creating objects and using data types isn't really mutually exclusive, you use both as needed.
> OOP does not mean "all methods are defined within the class declaration/file" a la Java, plenty of OOPLs allow external method definition. So it doesn't mean "well in OOP I always know the behavior of my class" when you have friend functions etc.
This is true. The main benefit of OOP in this regard is to help see the interactions between related groups of functions as organized into objects.
> OOP might mean "abstract classes" ie virtual methods. This leads us to inheritance, which is a) not confined to OOP and b) widely criticized. Remember that inheritance != polymorphism, c.f. Visual Basic for instance (at least VB5. Showing my age...). In practice, OOP usually invokes a great-chain-of-being-like hierarchy descending from Object, but again this is not universal.
Inheritance definitely has downsides and should be considered carefully when used, but it also has valid use cases. As with any language feature, it really is more of a question of is this useful to fix the problem I'm trying to solve? Granted, a lot of programmers (at least from the code I've worked on) seem to see inheritance as a universal hammer to their current problem nail :)
> OOP generally means "polymorphism", but the mechanisms vary widely. OOP's "Classic" inheritance-driven polymorphism is probably the worst way to do it, good for quick code-reuse and that's about it. "Interfaces"/pure virtual classes are a design pattern on top of abstract classes, better expressed as mixins or type-classes.
Whether mixins, type-classes, or a polymorphic inheritance is the right choice really depends on language and problem space. At least with mixins there are definitely circumstances where a mixin could have so many methods that it is essentially a form of multiple inheritance. Again, knowing the right tool for the job and knowing what limitations your development language has is more important than the existence of any one feature or tool.
> OOP generally implies strong typing but not always (python). OOP typing is quite clunky, especially in "noun-oriented" Java. You can make an argument that the rise of DI frameworks is in response to having impoverished type systems.
I'm not sure about DI being the result of impoverished type systems. Generally DI is about insuring that function dependencies are explicitly consumed rather than implicitly existing somewhere as a more global state. DI is more about contract enforcement on functions than anything else.
> My semi-rant here is because people say things like "do it this way, it's good OOP" without there being any agreement about whether we're discussing polymorphism, inheritance, encapsulation, factoring, normalization, or design patterns that are largely a response to the confusion.
This is definitely the crux of it. "Good OOP" is a meaningless phrase for the most part. What exactly is good for a project? Given the amount of tools available in OO languages, many different approaches could be used that would function as good based on your particular problem and developers.
> Colleagues & I once doubled system's functionality & replaced 750K lines of Java with 50K lines of ... Can you guess the language.
> Of course it was Java!
Another option is to use builders (that are mutable), to build/copy your immutable business (?) objects.
It is possible to have immutable objects in Java and have the equivalent of functional updates, but it's a hell of a lot of pointless boilerplate. It still beats traditional Java beans, though.
I suppose it's all about behaviour. If the class is literally just a struct - a box for data, there's no functionality to describe. Choosing public instance variables vs. getter/setter is just a matter of choice at that point.
The latter let you check Preconditions, etc. but that means that you actually have some invariant you intend to preserve (date of birth of the user cannot be in the future, for instance, so your well-formed user has some characteristics). Any members that can take any value their type permits should, in my opinion, just be public. Logically if you perceive that you could have some invariant in the near future, you'd want to have getters/setters but there's no point overdoing it.
(link provides no real details: http://openjdk.java.net/jeps/199)
If that is a goal of the sjavac project, then the ability to compile in parallel the different branches of the dependency tree for a set of classes would make for a major upgrade in user experience.
For example, with protocol buffers you end up doing things like.
AlbumCollection collection = user.getPreferences().getFavorites().getAlbums().toBuilder().addAlbum(album).build();
Favorites favorites = user.getPrefernces().getFavorties().toBuilder().setAlbumCollection(collection).build();
Preferences preferences = user.getPreferences().toBuilder().setFavorites(favorites).build();
and then you have to work your way up the chain of builders. Such a pain in the ass for something that could be much simpler with getters and setters.
user.addFavourite(album);You are right that normally you'd want the addFavourite method but in his example he is dealing with generated code which has a tendency towards verbosity.
You could add the method if Java allowed extension methods...
user.getPreferencesBuilder()
.getFavoritesBuilder()
.getAlbumsBuilder().addAlbum(album).build()That and good luck adding a new required field in your "constructor", because you just gave up on statically checking the parameters of the "constructor".
This is not a solution, this is a workaround.
Bollocks, there were already plenty of OO languages when Java appeared on the block.
The famous CLOS book was written in 1988, which makes use of slots instead.
I am at work now, otherwise I could provide more information.
My somewhat unorthodox rules for writing Java:
1. Don't use private. No reason to restrict yourself or others, and do extra typing. Friendly is a perfectly good default.
2. Don't use reflection. Reflection is only useful for making frameworks. Frameworks don't reduce the complexity of the problem you're trying to solve. Don't use them.
3. Don't use getters/setters. Sometimes they make sense for updating a cached value, or using a different underlying representation, but in general it's unnecessary clutter. If you still want them (e.g., for code style reasons), just generate them.
4. Don't use other people's code (tongue-in-cheek). If you use third-party libraries, consider wrapping them in your own interfaces as needed. This makes it easy to change the implementation and perform tests. It's not much effort, since you'll rarely use more than a limited subset of the functionality offered by the library. If you need a large subset, then just use the library directly.
5. Use final. Immutability makes programs simpler, more efficient, and inherently thread-safe.
6. Consider writing bean classes as follows. It's simple, efficient, thread-safe, and has a clean syntax (item.name):
public class Item {
public final int id;
public final String name;
public Item(int id, String name) {
this.id = id;
this.name = name;
}
}
7. Use an IDE, refactor, find references, generate code. It's easy to changes names and styles later, so just focus on important things like performance and reliabiltiy.8. Keep improving the way you write your code, don't listen to the crowd.
How do you account for value objects in that statement? Are you saying there should be no such thing?
So, a common use case might be loading data from a DB, changing several fields, then writing updates back to the DB.
class Rectangle {
num left, top, width, height, right bottom;
}
and can access like normal: var height = rect.bottom - rect.top;
But can later be changed into a computed property without affecting the above callsites, e.g: class Rectangle {
num left, top, width, height;
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
C# is a close 2nd, but it's not binary (or reflection) compatible to change from a field to a property for call-sites (i.e. it's only source-compatible).I'm surprised to hear that it's not reflection compatible. As a Java programmer, I assumed that was the main point of C# properties: Create a property now because there's no logic needed, but if you need logic in the future you can change the code and nobody outside needs to be aware of the change.
In .NET Reflection, Fields and Properties have distinct API's, i.e. fields can be accessed with `type.GetFields()` and properties with `type.GetProperties()`. The API's are basically wrappers around how they work, i.e. Fields let you get/set an instance's field value whereas with Properties you're instead invoking the properties getter/setter method accessors.
That's the point, but its not directed at reflection, and reflection goes around behind the scenes of the superficial access-notation compatibility. Which does make properties a badly leaky abstraction, which is problematic since their main reason for existing is to plug a leak in the abstraction provided by the method/field distinction.
Consistency of access in Java is also really problematic for the same reason. Which pair of getter/setter methods represents a reified property? This is often done by naming convention, that's usually, but not always consistent (getFoo/setFoo is common, but there's also isFoo/setFoo, isFoo/setIsFoo, foo()/foo(value), etc.). Worse (and this is something both Android's flavor of Java SDK and Objective-C have fallen prey to), not all properties are written symmetrically (e.g. getText() and the various setText() methods on an EditText in Android, although there are some where all of the setters are subclasses of the only getter -- even worse).
attr_accessor :left, :top, :width, :height, :right, :bottom
And you can change these to computed properties (regular methods) later without affecting the callsites
As an added bonus, you don't need to write foo.getBar(), you can just write foo.bar and it Just Works, whether foo.bar is a concrete implementation or a computed property.
Look at this blog post for example:
http://java.dzone.com/articles/java-properties-without
The sad thing is the request here is for something more ugly than what is really wanted (this is just automatic getter/setter implementation -- computed properties are better both for developers and consumers of their output.
class Blah(object):
foo = 2 # A normal property. Direct access
@property
def bar(self):
return self.some_lookup_method()
@bar.setter
def bar(self, value):
self.set_the_bar(value) // Sorry if there are any mistakes, I have not
// written any Java code for quite some time.
public class Point
{
private int x;
private int y;
.
.
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public void setX(int newX)
{
x = newX;
}
public void setY(int newY)
{
y = newY;
}
}
Look at how long the class definition is for something so basic!In Common Lisp there are two ways to define classes/structures, defstruct and defclass. Defstruct[0] automatically automatically defines everything for you:
(defstruct point x y)
will define the procedures make-point, point-x, point-y, (setf point-x), and (setf point-y). The cool thing is that they are all procedures. It easily change the class definition without changing the code that uses it. There are also some additional options for defstruct to specify default values, how to print the structure, as well as what prefix to use (the default is the name of the structure, 'point' in this case).Defclass[1], while much more verbose than defstruct, is much more powerful:
(defclass point ()
(x :writer set-x :initarg :x)
(y :reader get-y :initarg :y)
(z :accessor z))
will define procedures, set-x, get-y, z, and (setf z). Set-x and (setf z) are the setters, while get-x and z are the getters. To construct a point that is defined this way, one has to use the procedure make-instance which will take keyword parameters[2] :x and :y, for x and y respectively. [0] http://www.lispworks.com/documentation/lw445/CLHS/Body/m_defstr.htm
[1] http://clhs.lisp.se/Body/m_defcla.htm
[2] http://www.gigamonkeys.com/book/functions.htmlIt's just redundant code. Most of the time developers don't actually need to override the basic get/set operation on a variable. Yet you have to write the get/set methods over and over.
How do other languages address this issue?
Scala does a good job. You don't need to actually write a get/set method. But if you wanted to modify getFoo() you would simply implement the method with your custom getter
public int Age{get;set;}
no need to declare private variable, get or set methods.
foo.baz += foo.bar;
vs.
foo.setBaz( foo.getBaz() + foo.getBar() );
Interesting behavior.
Basically you keep states encapsulated without have to manually write methods,you just write methods when you need then.
Java verbosity on that matter is totally unecessary.
Granted when one use an IDE refactoring features can help,but still... A great strenght of the Java language is its stability.But stability doesnt mean a language needs to be that verbose.
This goes back to at least Eiffel (1985).
class Car
attr_reader :model, :company # only read
attr_accessor :color # read and write
endThis is pretty trivial so bear with me... If you have something that looks like this...
class Person
attr_reader :children
def initialize
@children = []
end
end
You can then do this... x = Person.new
x << "Bobby"
You will have then altered the value of @children without completely reassigning it.It is pretty astonishing they haven't done something about that. It doesn't seem like it should be a very hard language feature.
public class Foo { public readable int canSeeeMeButCantChange; public writeable int cantReadMe; public int existingBehavior; }
These are pretty simple changes to the compiler and verifier. You would make canSeeeMeButCantChange an invalid "left hand" variable in the compiler, and the verifier would have to check for any writes to the fields. cantReadMe would be an invalid right hand variable, and a similar check for the verifier. Any other public field behaves as normal.
Integer val = some.other.chain.of.objects.value;
In Java, this code has a huge potential for NullPointerExceptions. Instead a new operator (yes, I know) like:
Integer val = some.?other.?chain.?of.?objects.?value;
If any of the intermediate objects are null, the whole assignment becomes null. This could be done with a smarter compiler (easy way), or a new JVM bytecode (probably 'better' but not easy).
T obj = ...;
Optional.of(obj).map(T::some).map(U::other).map(V::methods).getOrElse(null);
Not quite as clean syntactically, but much more general, as the same operations can be applied to other monadic objects.
It may be a good thing to only support that sort of convenience for option types and not for nulls, in order to further encourage their use. Although using nullable types is already pretty darn convenient!
[0]: https://developer.apple.com/library/prerelease/ios/documenta... [1]: https://github.com/rust-lang/rfcs/pull/204
1) Lift regular values into monadic ones in a generic way. Let's say that we have two Monads - Optional and List. There should be a way such that we can take a non-monadic value (the part that will go inside) and turn it into a Monad. So, assuming Monad is a Java-like abstract class, the following should be possible:
Monad<String> m1 = Optional.lift("hello");
Monad<String> m2 = List.lift("hello");
2) Flat-map, typically called bind in this context. Given a monad and a function that takes a value and returns a monad, we should have some way of combining the resulting monads if we were to map this function over the first monad's internal value. So for instance, given an optional string, and a function that takes a string and returns an optional int, we should have some way of combining the Optional<Optional<Integer>> into just an Optional<Integer>. So, in the following contrived example... // Returns a UTF8 string value from a database, may fail
public Optional<String> getUtf8Name() { ... }
// Returns the length of a String if it contains exclusively ascii characters
public Optional<Integer> getAsciiLength(String str) { ... }
... you can compare the differences between it and the Functor's map: Optional<Integer> asciiLength = getUtf8Name().bind(getAsciiLength);
Optional<Integer> otherAsciiLength = getUtf8Name().map(getAsciiLength).getOrElse(Optional.absent());
As it turns out, you can implement the Functor's map method in a generic way using lift and bind. public abstract class Monad<A> implements Functor<A> {
/**
* Implements Functor's map method.
*/
@Override
public <B> Monad<B> map(Function<A, B> fn) {
return this.bind( innerValue -> this.lift(fn.apply(innerValue)) );
}
} Monad<String> m1 = Optional.lift("hello");
Monad<String> m2 = List.lift("hello");
Shouldn't that be Option<String> m1 = Optional.lift("hello");
List<String> m2 = List.lift("hello");
?I never did fill out a GEP but you could try your luck by subbing one, see http://docs.codehaus.org/display/GroovyJSR/Groovy+Enhancemen...
I'd be interested in seeing C#-like getters and setters. As long as they're just getting and setting, they're implied, but if you want to introduce a check or some other logic, you can do so without changing the signature of the class.
Groovy does some of this, but it requires you to use the name of the field - ie. person.age will check for a getAge() method first, then fall back on the "age" field. I quite like that methods have verb-names, but I don't want to verb my fields.
I was thinking this is more for _public_ variables... so like internally, a class could modify it's own readable fields, but code external could read only.
public int MyProperty{
get; //public
private set; //private-only setter
}
but obviously there are a lot of ways to skin that cat.Especially for private APIs i Java I have actually tended to default to public final members, without verbs.
We ran out of patience and switched to Scala. Never been happier :)
I love C#, but I do wish that setters weren't so easy to define (and that classes were sealed by default, and that fields were read-only, and that all extant warnings would become errors, etc.).
That being said, I still make my classes immutable unless there is a damn good reason not to.
State changes can have desirable side effects.If you expose an instance variable directly it's harder to encapsulate that.
Of course there are exceptions. If you have a class that is meant to be only a parameter bag(in an rest API for instance),that's ok,imho.
Don't get me wrong, I'm big on encapsulation and separation of concerns, etc. But you don't need to force "privacy" onto your class's users in order to achieve it.
The worst thing about having everything public (this is python, btw) is that sometimes it pollutes the auto-complete, and hinders discoverability. It's also not immediately obvious what the user should/shouldn't have access in your class.
Deleted comment
public T get_v() { return v; }
So far, not much difference. Both let the world access the variable, and both break encapsulation by doing so.
The difference comes when the class gets more complicated, and v changes. Now v might be null, whereas it never could be null before. But if it is, then what the rest of the world saw as v should now be some default value. So we can say:
public T get_v() { if (v != null) return v; else return default_T; }
and life goes on for everybody that was using v. But if all we had was a variable that everybody accesses, then all the users have to change. They either have to access the new getter or, worse, they each have to copy the logic to check for null.
This is how the getter encapsulates the inner workings of the class, and why it's a really good thing.
P.S.: How do I specify code formatting on HN?
public T get_v() {
return v;
}
See: https://news.ycombinator.com/formatdocThe contract basically says: "I will behave as you expect me to and as we agreed but only as long as you only interact with me in the predetermined(designed) ways that I allow you to"
Let's say you have
data Point = Point {x :: Int, y :: Int}
If you have a Point object called "point", you can get x by doing x_coord = x point
If you want to create a new Point with x set to 5, you can do point' = point {x = 5} type point = { x: int; y:int}
let z = {x = 5; y = 10}
let y = {z with x = 17} case class Point(x: Int, y: Int)
val p1 = Point(5,10)
val p2 = p1.copy(x=17)
How does F# handle nested data types? In Scala if you want to copy a case class of a case class (of a case class ...) it can get boilerplate-y as you have to copy outside-in through each property a la: x.copy(acase.copy(bcase.copy(cprop=1)))http://projectlombok.org/features/Value.html http://projectlombok.org/features/experimental/Builder.html
Although I prefer not using getters & setters at all.
Also, it breaks encapsulation, because your internal storage should be changeable without ruining your external surface area.
At least if it will be ever used by code beyond your control.
Because then you'll never be able to add a getter or setter later without breaking people's code.
Java is frustrating in that regard. As it should be able to deal with automatically invoking getters and setters when needed (it already inlines getters and setters at runtime, this is "just" the reverse), but it's a language decision that it doesn't.
As an additional bonus, this would help reduce the (legendary) verbosity of Java. a.b += c.d is much easier to read than a.setB(a.getB() + c.getD()). And don't get me started on Java's generics or lack of operator overloading...