Class BankAccount:
def __init__(self, accID, name, balance):
self.accID = accID
self.name = name
self.balance = balance
In the code above, why is it that I’m required to map all of my arguments to instance variables? This just seems like a waste of time. I’m using the exact same names, and the only difference is that I prepend them with the ‘self’ keyword. Why can’t I just use the argument names? In python, things seem to get rather unwieldy when an object’s constructor takes in many arguments.
I understand the obvious — that it is a requirement of the langugage — but I was wondering why virtually all OO languages are implemented this way.
1
Because of inheritance.
In a language without inheritance, the constructor could simply map its arguments to the object’s fields in a one-to-one manner. If the mapping isn’t one-to-one, you can always hide the constructor and provide a static method to do the work and pass the final values to the constructor. Case in point, this is how many functional languages handle it.
However, with inheritance, you run into a problem – you need to initialize the parent class’s fields. The language could force you to declare the subclass constructor such that it includes all of the parent class’s fields, but which values do you pass? The logic for initializing them is locked away in the parent class’s static factory method. You’d need to reimplement that logic, and that could be impossible if you don’t have the source code and the logic is undocumented.
That said, there’s no reason why the language can’t provide syntactic sugar for it.
1
There are cases where a simple one-to-one mapping is not appropriate. Automatically assigning parameters to instance variables only works sometimes, not all of the time. Perhaps validation is needed, or an exception might be thrown. Maybe a parameter must be scaled, or another object created.
Consider a Java BigDecimal. Internally it has a BigInteger and an integer scale. I see exactly one constructor out of many that accepts those two parameter types. Why go through the effort of having an automatic mapping that is of niche use a lot of the time? Most of those constructors likely have to perform additional processing to convert the parameters into its internal state. Those are a type of convenience constructor.
Furthermore, such a feature might encourage leaky abstractions. While that feature alone is not leaky, it could encourage lazy programmers to make all of the constructors they write to accept precisely the object’s internal state as parameters.
1
The purpose of a constructor method is to construct an object. Your constructor parameters are scoped to the constructor method, so unless you save them in instance variables, they are lost once your constructor method goes out of scope. This is how parameters work in any method; they are local to the method, not global to the class.
Your constructor method might simply map the parameter values to member variables, but it might do something completely different. Your programming paradigm needs the flexibility to allow you to do both.
Constructor methods typically don’t return anything. An ordinary method can perform useful work with parameters without involving instance variables, since you can actually return something from the method.
You usually don’t need to. Scala, for example, just keeps the arguments to the primary constructor in scope throughout the object’s lifetime. It turns out, the vast majority of the time that’s all you need, especially if you support default values.
However, you still have to support those other cases that the other answers enumerated. Most languages optimized their design to cover the largest number of cases consistently, rather than optimizing for brevity in the most frequent case at the expense of more complexity and less consistency in handling the less frequent cases.
Partially, this is because as a language designer, it’s difficult to tell what will actually be the most frequent case in the wild, or what the real-world consequences would be of sometimes holding onto a reference to a constructor argument that you no longer need.
I understand the obvious — that it is a requirement of the language — but I was wondering why virtually all OO languages are implemented this way.
Because there is a difference between the type (or type constructor) and the constructor (or data constructor). By mixing these concepts, you’re making assumptions about what the programmer wants – preventing them from having multiple constructors for the same type.
That said, C# 6 is introducing primary constructors to do this sort of stuff:
https://msdn.microsoft.com/en-us/magazine/dn802602.aspx
I also did this in an iteration of Tangent because I explicitly wanted to unify type constructors and data constructors, because by tying a single data constructor to a type made it much easier (read: possible) to mix the types together and still get a constructable type.
1
From a language structure point of view: Because of scope. Parameters passed in to a function are only valid and accessible within that function. Instance variables are valid and accessible in every function.
Furthermore, by definition function parameters are passed in to the function from a caller. So they do not reside within the object: they reside in the caller. They must, of necessity, represent two different physical areas in memory.
I suppose that in principle you could have a language where any parameters in a function that have the same name as object variables are automatically copied before the first line of the function is executed. My first thought is that that could cause trouble, because there are surely times when you would not want such an automatic copy. There might well be validity tests that should be done before saving any data. We might want to test if a new value equals the old value and so some logging. Etc. I suppose someone could reply that in that case you could just give the parameter a different name.
For two or three variables, I generally see it as no big deal. Yes, when there are 15 variables passed in and all have to be assigned to the correct object variable, it’s a pain. I’d be interested in seeing a language that had a feature to do this cleanly.
Frankly, what I usually do is create the object and then have a bunch of assignment statements. Like
myfoo=new Foo();
myfoo.bar=42;
myfoo.plugh="fwacbar";
... etc ...
This can be more clear than having a long string of values in the constructor, where it may not be obvious which variable each value goes to. (Especially small integers and Booleans.) It’s only slightly more typing to write the assignment statements rather than a long parameter list. In the not-uncommon case where the constructor is only called once or twice, it might be less typing, as it eliminates the parameter list and simply moves the assignments from the constructor to the caller.
Of course it has the drawback that it only works if all the values are straight assignments with no validation or manipulation. And in some cases we can say that a constructor with all the values produces a valid, usable object; while this technique means it almost certainly does not, which some consider a violation of the constructor contract.
3