SmellsLikeJava and C++, too.
Constructors are overloaded anonymous methods. It's impossible to neatly make two constructors that take one string and have that string mean something different to each.
I say: banish constructors from JavaLanguage and instead declare methods to be static, instance (the default), or new. They don't even need to return this - e.g. a "constructor" that makes a new instance and adds it to a pool.
-- PaulMurray
This is exactly how object instantiation is done in "real" object oriented languages, such as SmalltalkLanguage, RubyLanguage, EiffelLanguage, PerlLanguage, etc.
Suppose there where keyword/named parameters in Java, wouldn't the problem dissolve into nothing then?
AnswerMe: When would this capability be useful? An example would be nice.
"Ok, we have a ValueObject with a String foo and a String bar"
Obj(String foo, String bar)
"Dang! It may also have a baz, which means it won't need a bar" "What?? You mean your business database is not in third normal form?" "'Fraid so!" "Heretic! Heathen!
Blasphemer!"
Obj(String foo, String baz)
"Oops! Wont work - overloaded signature!"
Obj(String foo, String bar, String baz) // if baz is not null, then bar may be null
replace this with, (IMO)
class Obj {
public new Obj buildUsingBar(String foo, String bar) { ... }
public new Obj buildUsingBaz(String foo, String baz) { ... }
...
}
--
Static would work just as well here instead of new
--
Like others have said, real OO languages basically work like this already. But the other guy has a point, you're not passing in bar or baz, you're passing in string and string, so of course it doesn't work. Make a bar and baz class and wrap the string with them, and this would work fine, with existing semantics, and give you exactly the behavior you want, without requiring different constructor names, because let's face it, Java's not changing, CSharp's not changing, so what's the point.
Obj( Foo f, String foo )
Obj( Bar b, String foo )
Obj( Foo f, String foo, Bar b, String bar, Baz z, String baz )
where Foo, Bar, Baz are empty classes used only as tags. By golly, you are programmers, you are supposed to be capable of creative thinking! Oh, and quit using strings everywhere. If you want Perl, you know where to find it.
Make a factory if you don't like it. Constructors are very simple. Why do you want to make it more complicated? And if you want to make the constructor polymorphic then make a real class. Quit using strings everywhere.
I want to reinforce that point about the factory. Most constructors end up needing only a few options for a new() signature, in which case, the constructor is great. In cases where the constructor is not great, create several static/class factory methods that return properly constructed objects, and make new() private.
Or - if you're in Ruby land or using Java 1.5, use argument arrays, and parse out the contents (strong typing advocates, feel free to eschew this option).
--
Actually, better languages already do that, and it's not more complicated, it's simpler. Making it a real class doesn't allow constructors to be polymorphic; you need MetaClasses for that (see SmalltalkLanguage).
I believe they where talking about ParameterObjects here.
--
Regrettably, out here in the RealWorld we often build things from data in databases.
--
Um:
class CantDo
{
CantDo(string a)
CantDo(string b)
}
class CanDo
{
CanDo(RealClassA a)
CanDo(RealClassB b)
}
Oops, not sure what I was smoking. I thought he meant making constructors equal to other kinds of functions, i.e., virtual, overridable, and inheritable, something that metaclasses make natural since constructors are ordinary methods on the metaclass.
Why is it beneficial to separate object allocation and object initialization?
Coming from the world of CeeLanguage where there are no constructors, I found having a method combine memory allocation for an object with initialization of the object a significant benefit. Constructors help (but they are not perfect) avoid having a window where operations on an object cannot be called. I am not certain I understand the complaint above, and constructors are not perfect, but they are definitely a step in the right direction.
It is beneficial to separate object allocation and object initialization because you don't always want to allocate objects of a particular class in the same way. In C++, for example, you nearly always have the choice of stack based or heap based allocation. If you are working with shared memory, you may wish to allocate objects at a specific address using PlacementNew?.
Constructors are totally evil (see NewConsideredHarmful). I'm an OO guru; that means I'm an expert, not that I like it. You've got to know OO pretty damn well to really know the problems and limitations. You also need to know it in many languages, so you can distinguish language issues from those inherent to the design. (Same is true for any paradigm, I suspect. I imagine that much paradigm zealotry comes from those least experienced. The rest comes from people like you, who knows the value of a paradigm and sad to see it trampled beneath the feet of the ignorant. Unfortunately, you don't know the other paradigms well enough to make a proper argument about their limits.)
Re: "constructors are totally evil" - Well, that's an interesting generalization. I can see we are getting into philosophical issues beyond just GUI's. I'll have to ponder that one. I'm suprised nobody else challenged that one much. But there is something smelly about a bunch of routines with names like "initialize_and_display_foo()" or "update_and_display_foo()". If you see variations of "initialize_and_X" over and over, it implies an abstraction is needed, and constructors seem like the appropriate abstraction. -t
There are plenty of other abstractions available. Consider load = function(X) { show X; X.init(); }. Now you can use "load(X)" and "load(foo)", and you still aren't implicitly executing side-effects as a mere consequence of display-state (minimized vs. maximized, for example).
And the problems with constructors are that: (1) they hurt the GOD RAM illusion of having all objects in memory all the time, (2) which in turn hurts OrthogonalPersistence and TransparentDistribution... and automatic redundancy, duplication for locality of stateless objects, and a ton of other features. (3) They tend to execute while the object-configuration - or even the object - is still only half-defined. This hurts composition of objects... their constructors all need to be defined just right for them to compose. (4) There are gravely serious problems with cyclic references (e.g. for mutual interdependence) at construction time that take SelfDiscipline to avoid. (5) They harm optimizations! I.e. if you were writing an object configuration language, the use of constructors would make it extremely difficult to remove dead-code based on an object-reachability-graph; you'd also need to analyze for confinement of side-effects, which is much more difficult. (6) They are not abstract. (But see AbstractConstructor.) (7) The basic idea behind a constructor is to build the objects/data inside another one, which implies 'ownership' of that data and does not readily scale or compose.
- [I'm not sure I follow your argument here. I'll start with the first point, that constructors hurt the GOD RAM illusion. What exactly about constructors is incompatible with GodRam?]
- They aren't incompatible with GOD RAM. They are, however, incompatible with the GOD RAM illusion. The problem is that real RAM isn't infinite, relocatable, persistent, capability-secure, robust against crash failures, uniformly high performance, and global. GOD RAM is. We use idioms to construct elaborate illusions around our normal RAM to make it look and feel more like GOD RAM. Examples: (a) instead of a Singleton simply being a plain-old-reference to an object in a global address space, we use SingletonPattern to provide such a representation in a local address space. (b) we use complex caching schemes to make objects appear closer and more accessible than they really are, (c) persistence patterns and serialization are used for redundancy and 'transfer' of objects. The use of constructors hurts because they 'fire' each time an object is duplicated, moved, regenerated, shared, represented in a local address space, etc.. GOD RAM mandates they would fire at most once, regardless. (Use of constructors still has problems (3)-(7) even in GOD RAM).
- [When I referred to GodRam, I was already referring to it's illusion. Anyway, constructors shouldn't fire when objects are moved, regenerated, shared, represented in a local address space, etc. None of those acts are construction, so in an ideal language a constructor wouldn't be used (in spite of the current state of some popular languages). Duplication may or may not be an act of construction depending on whether the duplicate is intended as a cache or snapshot (where the duplicate is still intended to be the original object), or cloning (where the duplicate is intended to be a new object). If all those spurious constructor calls were removed, would there still be a problem?]
- If all of those spurious calls were removed (not a trivial task), you'd still have problems (3)-(7). But the GOD RAM issues would be gone and OO would be improved for it.
When a feature makes you fight the language to get other features, that's a
LanguageSmell. (on-display events have this same smell... but even worse due to composition and sharing issues.)
But there is a "confusion spike" in that sometimes you can just open the form/window and other times you have to call a subroutine before-hand to refresh stuff. It's usually better mental abstraction (MentalIndexability) to always just open the form and let it "handle itself". Otherwise, you have to concern yourself with the details of how its opened. Further, it reduces the chance that the form will be opened without remembering to initialize. Without your approach, one has to "just remember" to always open the form via the subroutine. With your approach, the guts are on the outside of the body. Optimization is a secondary concern to helping developers think clearer and avoid forgetfulness-related mistakes. -t
If you wished to abstract the definition of X to the point that 'show X' always executes 'X.on_display()', just like it abstracts other details (like rendering), that would still not involve on-display operations. In particular, 'show X' commands are always explicitly provided in some other input handlers. You would always be able to trace the call of 'X.on_display()' back to an original source user or server. This is different from true on-display events, which trace to a third party: the browser.
- Please clarify "'show X' commands are always explicitly provided in some other input handlers."
- I did clarify: You would always be able to trace the call of 'X.on_display()' back to an original source user or server.
- Perhaps you are confusing mere trace-ability with (what I'd call) easy trace-ability. I never claimed other approaches wouldn't be trace-able.
- I'm not talking about traceability except to say that there are only two parties - the user and the server. This is different from true on-display events, which trace to a third party: the browser.
- Anyhow, this all sounds like a battle of personal preferences, not some absolute advantage. The trigger results in a cleaner and simpler "mental" design in my head. It may be purely psychological, but PsychologyMatters. Humans maintain code, not computers; thus if the software better matches the human's head, it's generally easier to maintain. Your suggestion above makes initialization wag the dog's interface in my opinion.
- I do not see how psychology is involved here. There is a technical difference. And, while you say psychology matters, I suspect the 'on-display' trigger model only seems 'simpler design' in your head because you are less familiar with the other designs. I.e. I believe you're making an appeal to your ignorance, or even confabulating a justification for it. How do you know which is easier to learn or which better fits your head without having used both to equal levels of expertise? How are you controlling for your level of familiarity, such that you can isolate 'psychology'?
- It's simpler because I don't have to think about whether I call it one way if there is initialization and a different way if there isn't. Yes, I suppose one can "get used to" paying more attention to that issue, but one less thing to check is one less thing to miss and fill up your head with.
- Yes, taking away choice and control, so that you don't need to make any decisions, may make things easier for you... in general. Though, fundamentally, you're always free to use a procedure that takes away the arguments. No need for control, right? Anyhow, like I said (below), the problem you are describing is fundamental to ProceduralProgramming - which is based around the idea of saying how to do things in terms of sequential steps and parallel behaviors. There are many non-procedural designs where you don't need to think about the processing necessary for initialization, that completely eschew the issue of on-display events, and that provide many advantages for continuous update, shared access, and robustness to network disruption. You're just unfamiliar with them.
- Perhaps, perhaps not, but there's nothing wrong with on-display events, so there's no reason to go paradigm shopping. And it's not "taking away control". It can be done differently if needed.
- Sigh. There's nothing wrong with a TuringTarpit, so there's no reason to go paradigm shopping. And of course you're taking away control. If I write widget X using on-display events to refresh it, and you want to use it, you don't have any choice but to also use its on-display event. You can't separate the concerns of opening it and refreshing it. The only time you're not taking away control is if you're willing to rewrite a library from scratch. That's the nature of an appeal to a TuringTarpit.
- That's a "problem" with *any* black-box abstraction. Generally if we want to add a choice (feature) that didn't exist before, we'd use some kind of optional parameter with a default to the old behavior so that we don't break existing calls.
- Now that isn't true. There are black-box abstractions that make certain promises... e.g. "this is a black-box abstraction that has no SideEffects, is referentially transparent, and is guaranteed to terminate". Those guarantees offer programmers a huge amount of control over the nature of composed behaviors even when each behavior is a black-box, and merely offering a choice is incapable of offering these sorts of features. Being TuringComplete, SideEffects, On-display events for GUIs, etc. are among the so-called 'features' that kick controlled composition right in the nuts.
- If such exists, you haven't presented any above without references to non-mainstream paradigms.
- Black-box abstractions with documented limitations, assumptions, and rules-to-be-followed are common to libraries, frameworks, and protocols even when they are not enforced by the language. And to which non-mainstream paradigms do you refer?
- DataFlowProgramming and FunctionalReactiveProgramming.
- While those are fine examples of designs that allow languages to make certain promises for composition, I do not recall presenting or referencing them as such. ObjectOrientedDesign (following such rules as LiskovSubstitutionPrinciple) and the RelationalModel (which makes guarantees about the structure of each relation) and protocols like HTTP (which demands safety for GET and idempotence for PUT and DELETE) are all examples of mainstream programming designs that ensure black-box abstractions provide certain guarantees to give programmers greater ability to predict and control composition.
- Well, assuming we are sticking to procedural and OOP and fairly-typical GUI kits for now, you have not shown a net advantage. I only see trade-offs; different things get ugly under different situations. And when I weigh the trade-offs, the on-display approach overall seems the "cleanest" design by my assessment based on typical change patterns/frequencies that I observe and my personal MentalIndexability preferences. You've only demonstrated the existence of down-sides, not that the down-sides outweigh the upsides.
- Don't impose your artificial mental boxes on me. I refuse to wear blinders and limit lateral thinking by "assuming we are sticking to procedural and OOP". I also cannot consider speculation about relative MentalIndexability of techniques you don't know very well to be unbiased or scientific - claims that PsychologyMatters have just as great a burden of proof as anything else. What is this 'change pattern' you see as beneficial that isn't equally met by the alternatives? (And don't appeal to BadCodeCanBeWrittenInAnyLanguage.)
- You haven't proven that psychology doesn't matter. That's not the default either.
- True. But none of my assertions hinge upon psychology mattering or not mattering. PsychologyMatters is premise to your argument. That claim is yours to prove, not mine to disprove.
- Similarly, you are assuming that psychology is a non-factor, and are thus ignoring it for your summary assessment. You cannot just hand-wave it away because you don't like it or because it's difficult to measure (SovietShoeFactoryPrinciple).
- I'm assuming no such thing: none of my arguments hinge upon psychology being a non-factor. But, it would be irrational for me to consider such things as the price of tea in China, my favorite color, the crashing 2009 economy, and psychology to be relevant and significant 'factors' in this discussion or any other until I have strong reason - such as evidence or a known logical relationship - to believe so. If your claim is difficult to measure, that is your problem because PsychologyMatters is a premise upon which you are hanging your arguments.
- The "outer" problem with your approach if you stick to the listed paradigms is that it either requires an inconsistent interface where some call a subroutine and some call a method, or you wrap everything in a subroutine and have to create or delete the matching subroutine every-time a new form is created or deleted (MirrorModel). If you *don't* stick to the listed paradigms, then your "constructors are evil" claim should only be limited to cases where your other obscure paradigms are used.
- I disagree, but it seems I've not well communicated the crux of my argument. ConstructorsAreEvil is not an appeal to simply eliminate constructors, leaving a vacuum in the role they once fulfilled. ConstructorsAreEvil is an appeal to replace constructors with weaker specialized alternatives about which more guarantees can be made to better support object graphs, well-defined initialization and finalization of objects, more optimizations, and the GodRamIllusion. This is similarly true for OnDisplayEventsConsideredHarmful and NewConsideredHarmful. The idea is to remove then replace the offending feature, not to excise it and leave a vacuum. Reasonable sources for alternatives to constructors and on-display events may be found in other paradigms.
- Your conditional initialization situation will indeed gum up my original design somewhat, but not any worse than yours, and it only need be done if it actually happens, not all the time. In other words, yours is ugly all the time, while mine is only ugly under certain circumstances, and that's only if parameters are not easy to have or emulate. -t
- I do consider the procedural approach 'ugly' for on-display events, but there are beautiful alternatives that simply reject the procedural paradigm. Also, procedural 'on-show' hooks (that fire X.on_show() when you first explicitly call "show X") are not what I consider to be on-display events unless they also occur implicitly from manipulations to the browser. (See OnDisplayEventsConsideredHarmful for my working definition of the term.)
- I suspect this is all a ploy to "advertise" your obscure paradigms/techniques, and I'm growing bored with it. I don't question that every paradigm/technique has specific cases where it shines slightly brighter than the alternatives. However, I'm generally against paradigm potpourri just so that each can have its narrow day in the sun. (ParadigmPotpourriMeansDiminishingReturns) -top
- I'm against LanguageIdiomClutter and ThereIsMoreThanOneWayToDoIt, whereby language primitives and standard library components compete for territory. Language primitives and features are something definable. I can't say the same for "paradigm potpourri". What is it, exactly, that I'm promoting and you're railing against?
- I'm against those also, but weighed in using a balanced way with all the other avoid-X factors (WaterbedTheory). Let me ask you this: suppose the shop manager mandated that we use only SQL-RDBMS, OOP, and procedural("SOP") for all shop projects. Could you objectively "prove" your suggestion is net better than mine (constructors) sticking to SOP? Or, does the improvement require the other paradigms/frameworks you mentioned?
- Whether I could "prove" the suggestion is "net better" depends on how you define "better". If you define "better" as "easier to implement without introducing infrastructure while keeping my hands tied to satisfy language and framework constraints introduced by my shop manager for no technical reason whatsoever", then no, I probably could not prove it better. But if you define "better" as "able to achieve more features among CrossCuttingConcerns including such things as performance, safety, security, persistence, distribution, concurrency, consistency, scalability, disruption tolerance, determinism, and termination" then, yes, I believe it will objectively prove "better" to eschew constructor events. (One would need to replace it, though. With my hands tied by your pointless MentalMasturbation "rules" restricting me to OOP/Procedural/Relational, I would probably replace constructors with a three-phase OOP/Procedural behavior: allocate then link then init().) Also, since it seems you've since confused the point, the mentions of the DataflowProgramming and FunctionalReactiveProgramming apply as alternatives to on-display events, not constructor events.
- It is not unrealistic for a shop put limits on style. Thus, I object to your derogatory labeling of it. Peers and managers grow uncomfortable if you use styles or tools that deviate too far from the norm of the shop. There are formal standards and informal (unspoken) standards for every shop. I've gotten the "evil eye" for violating them multiple places before. I shape up and stay with the conventions if I want my paycheck. (Sometimes it's good the other way, like the time it stopped the Mad XML Hatter from XML-tizing everything and everyone.)
- People, including managers, often do things that deserve severe derision. The basis for your objection seems logically equivalent to saying: "murder and rape are not unrealistic, thus I object to derogatory labeling of them." To me, that seems irrational.
- There are valid business reasons to use existing tools (because they're "existing" and "proven"), but the fact is that doesn't apply in this case: other approaches are also existing and also proven, and in a sane IT shop one could take other proven technologies to the manager and make a case for adapting them rather than moping about and living with pointless challenges because you're afraid of getting the "evil eye". If the manager can make a good case in return, then so be it, but a blanket mandate "for all shop projects" as you suggested indicates only a lack of competence on his part. Your unwillingness to confront the manager indicates a lack of professional competence on yours.
- My reply started to resemble the umpteen other golden-hammer "evidence" debate topics, so I'll let those do the answering. (Links to be added incrementally).
- You have quite some double-standards, TopMind. When it's time for someone else to prove something, it's "golden-hammer" time. When it's time for you to defend your designs, your standards are that you "don't see them causing mass GUI car accidents and dead kittens."
- I see no problem with people using what they've been using and are used to until shown something clearly better. Your pet techniques are relatively obscure in the GUI world. That's not my fault.
- No... it is pretty darn common in the GUI world to eschew SideEffects on-display. You certainly won't find scene-graph languages or a ZoomableUserInterface like Microsoft Seadragon using them. OpenGL is procedurally specified but functional under-the-hood. When it comes to constructors, a quick overview would reveal some similar things: systems that support object-graphs (e.g DataflowProgramming languages, Unix PipesAndFilters) invariably have ways to restrict side-effects from touching other parts of the graph before everything is allocated and linked (basically alloc->link->init pattern) and often drop the 'init' phase since it still hurts optimizations. DataflowProgramming and FunctionalReactiveProgramming are extremely common in GUI systems (Nuke, ICE, Max, and many more). Your ignorance of the GUI world and the reasons behind various design decisions is not my fault.
- But you've made it pretty clear that it's not just "constructors" that are "evil", but an entire approach. You want to overhaul the app language and GUI system with your pet tools that you personally feel are better. The reader of this page will not find a relatively-simple alternative to constructors that is better by itself, but rather a round-about plea to overhaul the whole shebang. Thus, the title is a bit misleading. I'd suggest a title of "constructors-are-a-symptom-of-a-bad-paradigm" or the like. You've gone into Xanadu Mode again. -top
- It is true that constructors aren't the only failing of modern languages. To suggest otherwise would be ridiculous. But, while I do aim to achieve a design without those failings, the case made on this page is ConstructorsAreEvil mixed with a bit of OnDisplayEventsConsideredHarmful (only because the latter topic did not exist when content was moved here by someone). And your other statements are simply untrue: I have not been promoting any particular "pet tools", I have provided a relatively simple alternative to constructors (alloc->link->init) and other alternatives are readily available on this WikiWiki, and "symptom-of-a-bad-paradigm" is unreasonable because contructors are not an accepted part of ANY paradigm. Even though NobodyAgreesOnWhatOoIs, you won't find "constructors" among any of the popular proposed definitions.
- Although OO often gets credit for them, they are perhaps a cross-paradigm idiom, related to triggers. Anyhow, I don't see them causing mass GUI car accidents and dead kittens, so I will continue to use them until SHOWN the alternatives are CLEARLY being better without their own set of gotcha's. -t
- It's nice to know just how low your acceptability standards go. I feel sorry for your clients. Anyhow, merely trading constructors for the simplest alternatives only gives you the potential to become better, without being any worse. It allows you to add various other features currently made challenging by dependency upon constructors and the potential for SideEffects from them. (Such features include: orthogonal persistence, transparent redundancy and distribution, copying GarbageCollection, application configuration languages, safe cyclic object-graphs, dead-code elimination, high-performance object-slab allocations.) You seem to want a dramatic, in-your-face 'evil' that is clear even when you aren't interested in noticing. This is more of a "pouring wine from a led pitcher" evil. It poisons and taints languages and projects in non-obvious ways, diminishing their maximum potential for brilliance.
- That's coming across as BrochureTalk. I want to see realistic scenarios and realistic code demonstrating X being better than Y.
- You seem to be of the belief that example code can readily demonstrate a categorical advantage or the limitations of a technique.
- Yes, I do, or at least some number-returning metric. If you can't do either of those, then I shall dismiss you as either a charlatan, or a horrible articulator/documentor. I have standards for evidence of objective claims. -t [Note: I split the surrounding paragraph].
- I don't really feel like indulging your naive whims, especially if it's because you're unwilling or unable to confront the logic presented. Anyhow, I think I'll leave off this conversation until someone to whom the constructor issues actually matter is interested. It isn't as though constructors will kill kittens, after all. They'll only kill your project in the long-term.
- Sorry, I don't see any "logic". Please reformat it in a geometry-like proof form if you feel there is solid logic in here somewhere. I just see the horse droppings, I don't see the horse.
And if your objection is that people are abstracting and concerning themselves with details of
how things occur, then the real problem you're complaining about is the use of
ProceduralProgramming. Consider a more declarative or rules-driven approach, perhaps
DataflowProgramming or
FunctionalReactiveProgramming. Having a display that continuously updates based on changing external data based entirely upon a declarative description of the data-source requires even less concern for 'how' a display is opened and 'how' it maintains itself.
Please note that I didn't exactly read the whole discussion, but I do agree somewhat with the sentiment at the top of the page. I think that this might be the reason the original poster thought that "new" methods would be a good idea.
You see, the problem with constructors is that they are necessary. You need to write a ctor to initialize a class.
class Obj {
public final String foo;
public final String bar;
public final String baz;
private Obj(String foo, String bar, String baz) {
this.foo = foo; this.bar = bar; this.baz = baz;
}
public static Obj withFooAndBar(String foo, String bar) { // In Objective-C, this would be withFoo: andBar:. I'm trying to emulate that.
return new Obj(foo, bar, null);
}
public static Obj withFooAndBaz(String foo, String baz) {
return new Obj(foo, null, bar);
}
}
Whereas with the proposed syntax, one could do this, instead:
class Obj {
public final String foo;
public final String bar;
public final String baz;
public new withFooAndBar(String foo, String bar) {
this.foo = foo; this.bar = bar; this.baz = null;
}
public new withFooAndBaz(String foo, String baz) {
this.foo = foo; this.bar = null; this.baz = baz;
}
}
Ironically, this syntax creates more typing, which I'm sure the original poster did not intend. It does, however, make all initializer functions use the same syntax.
Some languages which do this sort of thing easily are:
//Scala.
class Obj private (foo : String, bar : String, baz : String) // Never mind the fact that if bar and baz were mutually exclusive, a guru Scalite would use Either[String, String]
object Obj {
def withFooAndBar(foo : String, bar : String) = new Obj(foo, bar, null)
def withFooAndBaz(foo : String, baz : String) = new Obj(foo, null, baz)
}
In
ScalaLanguage, you write the constructor as arguments to the class, with a private designation if need be. The params then become member vals. Because of some special rules in Scala,
all construction of objects
must be done through constructors written in this way. (You can write more constructors, but the last thing all constructors must do is call the original constructor.)
# Perl Six.
use v6;
class Obj {
has $.foo, $.bar, $.baz;
method new(*@_, *%_) { die "Cannot instantiate Obj through new." }
method withFooAndBar($foo, $bar) {
bless *, :$foo, :$bar; # Bless works with all classes. :$foo is short for :foo($foo), which in this case means "initialize member variable foo to $foo.
}
method withFooAndBaz($foo, $baz) {
bless *, :$foo, :$baz;
}
}
As you can see, neither approach actually forces you to write a constructor, although one makes you write its signature--and that one actually saves you time, as you would have written out the member variables anyway, right?
See DeterministicResourceManagement and to ResourceAcquisitionIsInitialization for related issues about constructors.
CategoryEvil
JuneZeroNine