Open marcusnaslund opened 8 years ago
Isn't super ruby-like just forwarding its arguments?
The compiler does forward all the arguments. You can find the related lines around rock/middle/FunctionCall.ooc: line 428. But I don't know what the "expected action" should be.
What if a zero-argument constructor is added in Base
? Should the value still "magically" end up in x value
, or will the constructor in Derived
have to be modified to call super(v)
instead of super()
for that to happen?
If change the test code to
Base: abstract class {
value: Int
init: func (=value)
init: func~nodefault ()
}
Derived: class extends Base {
init: func (v: Int) {
super()
}
}
x := Derived new(3)
x value toString() println()
It wil print 0
instead of 3
, because init: func
has higher matching score than init: func(int)
.
Thanks for clearing that up - I don't recall it being possible to call super()
unless there was a matching zero-argument function in the base class.
So... modifying Base
by adding a zero-argument constructor will make Derived
call a different function. If this were my program, I think I'd want to be explicit about which function super
refers to by calling super(v)
instead of super()
, then, instead of relying on the arguments being forwarded and possibly calling the wrong function if the base class changes.
Yes, if you call super(v)
explictly, it will finally match init: func(int)
, and the forwarding will not happen.
However, currently compiler will ignore the suffixes of super, so if we have
Base: abstract class {
init: func~a(arg1: Int)
init: func~b(arg2: Int)
}
super~b()
may no result a call of init~b
as both init~a
and init~b
have the same score.
The following patch makes super
+~suffix
available.
diff --git a/source/rock/middle/FunctionCall.ooc b/source/rock/middle/FunctionCall.ooc
index 1049553..4a831b2 100644
--- a/source/rock/middle/FunctionCall.ooc
+++ b/source/rock/middle/FunctionCall.ooc
@@ -417,7 +417,7 @@ FunctionCall: class extends Expression {
fDecl := trail get(trail find(FunctionDecl), FunctionDecl)
superTypeDecl := fDecl owner getSuperRef()
finalScore := 0
- ref = superTypeDecl getMeta() getFunction(fDecl getName(), null, this, finalScore&)
+ ref = superTypeDecl getMeta() getFunction(fDecl getName(), this getSuffix(), this, finalScore&)
if(finalScore == -1) {
res wholeAgain(this, "something in our typedecl's functions needs resolving!")
return Response OK
By the way, I would suggest using the super modifier in the function prototype if you need to call the super function anyways.
If you do need to call it conditionally, using all the arguments would obviously be better form, since the addition of a zero argument version of the function would alter behavior.
"the super modifier"?
Yes, you can do something like:
Foo: class {
init: func
doThing: func (x: Int) { "Called Foo doThing with #{x}" println() }
}
Bar: class extends Foo {
init: super func
doThing: super func
}
It doesn't allow you to add call though, it's pretty much only useful to inherit constructors, since you are required to do it in some cases.
IIRC the tutorial mentions this as a "hackish workaround"?
IIRC the tutorial mentions this as a "hackish workaround"?
I don't remember exactly, but perhaps the issue with the super
modifier isn't the spec but its implementation.
The implementation looks fine (does what I expect) to me and I don't particularly recall it being considered poor style.
Anyway, the use case is rare, I just think it's more elegant to inherit a constructor that way than just using a super call in the body.
Here is a simple example:
Even though
Base
has no zero-argument constructor, this code still compiles and runs just fine. Thev
passed toDerived
constructor magically ends up invalue
.