+ 6
Constructor Delegation Or Default Arguments?
Two possible ways to increase constructor flexibility look relatively similar to me in result: Classname(char name): Classname(name, 0) {} // Constructor defi following later Classname(char name, int age=0): name{name}, age{age} {} When should we delegate to another constructor and when rather use default args?
22 Respostas
+ 2
HonFu Well I was commenting on the expressiveness of the type system which only Haskell folk care about anyway. And C++ generics can do things python type hints can't. I think you'll need to pick up Haskell to get "kinds", we usually don't really talk about them in programming.
`reinterpret_cast` is unfortunate but even Haskell gives you `unsafeCoerce` which can turn anything into anything else. Sometimes you just need to do unsafe stuffĀ and backdoor yourself I guess.
And yeah exactly. The default constructor does the lowest common denominator work that all constructors have in common and in the others you delegate, and then do some stuff on top of that.
+ 6
I use default arguments whenever prossible because it's shorter, but usually I find that the default constructor does all the heavy lifting so I end up delegating to it most of the time.
Like, all the "embellished" constructors that take more args usually want to do all the same things as the default constructor plus more, so not delegating would mean duplicating code which is of course bad.
+ 6
Schindlabua, the book I'm just reading gave an example where the delegation was really just another way of doing what default arguments do.
But I suspect it was just an awkward example that didn't really serve to show how delegation can add value, and from my level I have trouble imagining a real use case.
Do you know from the top of your head one or two simple examples where delegating really makes a lot of sense?
+ 5
Does this add any value?
https://stackoverflow.com/questions/31162795/object-construction-default-parameter-vs-delegation
+ 5
Schindlabua C++'s stronger type system? Didn't we say in another post that python is more strongly typed than C++ ?
+ 4
HonFu Sure! For example you write a class that connects to a chat network.
The default constructor with zero args opens a TCP connection, authenticates with the chat server, etc.
Then you offer a second constructor that takes a string which is your nickname in the chat network.
So `new Chat("HonFu")` would then delegate to the default constructor, which does all the work, and then in the constructor body you send "SET nickname = HonFu" over the wire. You've achieved seperation of concerns and didn't have to dupe code :)
You could then add a third constructor that delegates to the second, and also joins you into various chatrooms. etc!
EDIT: I guess in general, whenever a default constructor does more than just setting instance variables to some value, you end up delegating to it a lot of the time. Opening files or other resources that persist during the lifetime of the object come to mind. Database connections, files, other objects created in the ctor, you name it.
+ 3
HonFu Yeah in python thats not really a concern because it's an interpreted language but `if(name.length())` immediately strikes a sour note for me because you're doing work at runtime that can easily be offloaded to the compiler (by delegating!)
And that approach pretty much fails when you have, say, a generic parameter instead of a string. I guess you can do null checks but that runs into it's own host of problems.
I'm sure it'll become second nature once you're used to C++'s stronger type system!
Maybe my example also wasn't the best. Consider instead some class where you have two one-parameter constructors, each taking a different type. I guess then you absolutely either have to delegate or copypaste code.
+ 3
Sonic "strong typing" isn't rigorously defined but yeah I meant staticness in particular whereas python's is dynamic. Python's type system is also weaker in the sense that you can express types in C++ that you can't in python ("higher-kinded types").
Of course C++ has `void*` and `reinterpret_cast` which means everything can be everything else but if you pretend these don't exist the type system is decent. But that's just a side note.
HonFu Depends I guess. Take the chat example, you could have a ctor that takes a string for the username and another ctor that takes a custom user-object which is part of your chat framework thing. Then both delegate to the default ctor.
+ 3
Schindlabua, I'm not sure if classifying a language while ignoring a big part of their traits is the right way to go.
In another of my questions there was discussion about privacy. The pythonist writes a _ in front of a name and says: 'This is private by convention.'
But you can access the value anyway if you don't care about the convention. You are not hindered in any way really.
Just as you're not hindered in the Cs to let all sorts of (even harmful) auto-converts happen.
Shouldn't we classify a language rather by what it doesn't allow us to do *even if we want*?
(But this just as a side note. š
)
+ 2
Schindlabua, Sonic, sorry for being late with my reaction.
I still have some trouble seeing the difference. I think this might be because I subconsciously think in Python, where in many cases there's just one way you'd do something.
To take Schindlabua's example: The only difference seems to be that a string is handed over or not, right?
So wouldn't it be simpler to just write something like:
Classname(string name="")
and then decide by the given arg situation what happens in the constructor? Like:
if(name.length())
// do this and that using name
I'd find that easier to understand because there'd be just one constructor and not the illusion by delegating that there are several fundamentally different things.
In an earlier version of your former post you connected delegating to separation of concerns; but isn't it rather the opposite? Different object initializations look like they'd call different constructors while in reality they all end up in the same...
+ 2
Schindlabua, ah, okay, compile what you can instead of runtiming it - that actually makes sense (typical blind spot of a pythonist I suppose).
If I have a class that's either initialized by two different types, let's say an int or a string, wouldn't I then need to have two separate constructors in the first place instead of delegating?
+ 2
Sonic, I suppose he meant 'static' which feels more safe to those who are used to it, and therefore 'strong'. I just translated it in my mind. :)
+ 2
Schindlabua, (back to topic), so the argument is either a string or a custom user object.
But if I delegate to the same constructor in both cases, how will it work? One constructor will prescribe a certain procedure, and if the type of the object is different, isn't there a need then to handle the specifics of the two constructors for two different types of args?
+ 1
Schindlabua, ah, so does that mean, first the delegate is executed and then the actual block of what comes after the delegation?
Although it's not totally the same, would it be structurally a bit like inheriting and using 'super' to call the constructor of the base class and then some other code? (Just not with inheritance obv. ^^)
+ 1
Yes pretty much!
+ 1
Okay... then I think I finally got it.
Thanks for the patience - this was rather slow from my side. š
C++ has so many patterns; it's hard for me to tell what is just an atavism for legacy code, or just synonymous, or syntactic sugar - and what actually does something, however subtle.
I'd like to take a look into Haskell, I hope they (you?) will bring it here someday.
+ 1
np :P Wish I had though of the superclass analogy, that's a good way to think of it.
I'm sure you'd like Haskell! I first picked it up reading "Learn you a Haskell", it's pretty nice. Check it out, it does a better job than I could ever do!
+ 1
Thanks, I'll consider it!
I have read, Haskell only knows recursion, not iteration... that true?
Might be a bit troublesome for me.š
+ 1
I guess that's technically true but you usually use the map/filter/... functions instead of recursing by hand.
And then you chain those functions together to write more complicated functions.
Python-esque list comprehensions are also very common which I think counts as iterative :P
+ 1
Are those comprehensions formed using the word 'for' or does Haskell deny any relation to primitive iterative ancestors? š