I want to call a method (foo) in Coffee-script from a subclass. I know I can do this with #foo if I didn't overwrite foo in the subclass, or with super if I did overwrite it and I'm calling from the subclass' foo method.
However, I would like to call superclass' foo method from subclass bar method. How can this be done?
Not sure why you need this but ...
class A
foo: ->
console.log 'A'
class B extends A
foo: ->
console.log 'B'
bar: ->
A::foo.call #
new B().bar()
Related
Why does the following code print "BaseP" at #2?
protocol BaseP { func foo() }
extension BaseP { func foo() { print("BaseP") } }
protocol SubP: BaseP {}
extension SubP { func foo() { print("SubP") } }
class C: SubP {}
let subP1: SubP = C()
subP1.foo() // #1 prints "SubP", fine.
class BaseC: BaseP {}
class SubC: BaseC, SubP {}
let subP2: SubP = SubC()
subP2.foo() // #2 prints "BaseP". why?
In both cases we call foo() on a reference with a static type of SubP,
referencing an object with a dynamic type that is a class conforming to SubP.
Even if it was a static dispatch, I'd think that it should still call SubP.foo().
Why does the base protocol implementation get called at #2?
Also, why does inheriting from BaseC make a difference
(if in the class SubC line I remove BaseC or replace it with BaseP,
then it suddenly prints "SubP")?
When you call subP1.foo() or subP2.foo(), you are calling the foo that satisfies the protocol requirement foo in BaseP. (i.e. the method that witnessed BaseP.foo). There can be only one such witness.
The other important thing is that the foo requirement is not in SubP, but in BaseP. The only requirement of SubP is that the conformer has to also conform to BaseP.
In the case of subP1, C directly conforms to SubP. To resolve the only requirement of SubP, C has to also conform to BaseP. Now the compiler needs to figure which method can witness foo. There are two methods available, but the one from the SubP extension hides the one from the BaseP extension, so the one from the SubP extension is chosen to be the witness, so you see SubP printed.
In the case of subP2, the witness of foo is already decided when you conformed BaseC to BaseP. Here, there is only one choice - foo from the BaseC extension. When you later conformed SubC to SubP, the only requirement left is that SubC should also conform to BaseP. Well, you said SubC inherits from BaseC, so that's fine. The compiler is happy, and foo from the BaseP extension ends up being the witness.
Given there is something along this lines:
class Foo {}
class Bar extends Foo {}
class Baz extends Foo {}
I find myself writing this type of code:
if (foo is Bar) {
(foo as Bar).doSomething(); //Compiler warning of unnecessary cast.
} else (foo is Baz) {
(foo as Bar).doSomething(); //Compiler warning of unnecessary cast.
}
I don't know how to avoid this situation.
If I remove the check types of of is Bar or is Baz before the cast I may get a runtime error and if I don't cast, it means no access to the public stuff on that type.
Maybe I follow a flawed code design that I need to update because I believe I should avoid checking class type.
Is there any method in Dart that may help here?
(foo as? Bar)?.doSomething() (swift like)
Actually you can just do foo.doSomething(); instead of (foo as Bar).doSomething(). The compiler knows that if the condition if(foo is Bar) turns out to be true, the variable foo in that block of code is of type Bar.
Try:
if (foo is Bar) {
foo.doSomething(); // It's automatically inferred that type of `foo` is `Bar`
} else if (foo is Baz) {
foo.doSomething(); // It's automatically inferred that type of `foo` is `Baz`
}
Hope that helps!
With objects oriented languages this kind of if/else or switch statements based on class are solved using polymorphism. If doSomething() is in clase Foo the compiler knows that no matter run time type the method is defined on any child of Foo.
Then if you know that foo is Foo, Bar or Baz you actually should only use foo.doSomething(), no type check and no cast.
The only thing that you need to be aware is to validate that foo is Foo, make sure to use type and not var or dynamic:
void doSomething(dynamic foo){
if (foo is Foo) {
foo.doSomething(); //Ok with Foo Bar or baz
}
foo.doSomething(); //Possible runtime error since foo can be anything
}
Since dart is typed is a good practice to use types and not dynamic and you can write directly something like:
void doSomething(Foo foo){ //Making sure that you will work with a Foo
foo.doSomething(); //Ok with Foo Bar or baz with no check
}
I am trying to call an initializer required by protocol A on a type that both conforms to A and is a subclass of C.
All is fine and good if C is a base class. But as soon as C subclasses another class, say B, it breaks.
Here's what I am talking about:
protocol A {
init(foo: String)
}
class B {
init() {}
}
class C: B {}
func makeSomething<T: A>() -> T where T: B {
return T(foo: "Hi")
}
That works. But if I change where T: B to where T: C, I get the following error: argument passed to call that takes no arguments. It will only allow me to call Bs init.
Why can't I call this initializer? I understand that the super class has its own designated initializers that must be called. But that will be enforced when someone actually writes the class that subclasses B and conforms to A. (E.g. implementing init(Foo: String) and calling super.init(bar: Int) inside).
Any help here would be greatly appreciated. Thanks!
Swift provides a default initializer for your base class if it has all properties initialized but not incase of Generics because Swift may think its properties has not been initialized.
So when you constraint your return type as
func makeSomething<T: A>() -> T where T: C
It requires initialization for class C as Swift cannot provide a default initializer.But if your remove the where clause everything works fine
func makeSomething<T: A>() -> T {
return T(foo:"string")
}
If you want to return return T(foo: "Hi") :
You are getting error because class C doesn't have initializer that accepts init(foo: String)
Change your class C as
class C: A {
required init(foo: String) {
}
}
which provides at least one initializer that accepts the argument type.
So, remember if you don't subclass There is already one initializer doing your job and you dont get error.
Is there a way to assign a function with a parameter that is a subclass to a function variable with a parameter that is its superclass? Here is an example of what I mean:
class ClassA {}
class subclassOfA:ClassA {}
func subclassToNil(argument:subclassOfA) -> (){}
var functionVariable:(ClassA->())
funcVar = subclassToNil
This raises a type incompatibility exception.
I'm afraid not--you've discovered "covariance" and "contravariance". Function types are contravariant with their parameters (arguments), which means you could supply a superclass if you wanted, but not a subclass. With return values on the other hand, function types are are covariant and could return a subclass if you'd like.
With a little thought, these rules make sense:
class ClassA {}
class SubclassOfA: ClassA {}
func subclassToNil(argument: SubclassOfA) -> ()) {}
var functionVariable: (ClassA -> ())
functionVariable = subclassToNil
functionVariable(ClassA()) //`subclassToNil` won't know what to do with this; kablooie!
However:
class ClassParent {}
class ClassA: ClassParent {}
func subclassToNil(argument: ClassParent) -> ()) {}
var functionVariable:(ClassA -> ())
functionVariable = subclassToNil
functionVariable(ClassA()) //`ClassA()` is indeed a valid `ClassParent`, so we're fine.
So it's safe to use parameters that are less specific. The reasoning for return values is very similar, and you'll see that logically, you can use ones that are more specific.
This is only an example of what i am trying to do:
class Test{
class func b(){
a()
}
func a(){
println("A")
}
}
And in a other swift file i do:
Test.b()
But i get an error when i call a() in my Test class it says: missing argument in call
If i write a( it suggest me to call the method like this: a(Test), Test for the name of the class. So i try giving it the parameter self but it doesn't works
As #matt said, b is a type method (or class, or static, however you want to call it), and requires a type to be executed (which in your case is Test):
Test.b()
On the other hand, a is an instance method, and requires an instance to be invoked.
So the only way to call a is with an instance of Test:
var test = Test()
test.a()
If you want to call from b, you have to either create an instance of Test in b:
class func b() {
var test = Test()
test.a()
}
or pass an instance of Test to b:
class func b(test: Test) {
test.a()
}
However I think there's a flaw in your design. b should not be a class method, unless you use it to create an instance of Test to return to the caller:
class func b() -> Test {
var test = Test()
test.a()
return test
}
There might be other cases when this kind of interaction can be useful - maybe if you explain what you are trying to achieve, we can provide a better answer.
Side note: the reason why autocompletion proposes Test is that instance method are curried type methods, taking an instance at the first call:
var test = Test()
test.a()
// Is equivalent to:
Test.a(test)()
The function a is an instance method. The function b is a class method. A class method cannot call an instance method, as there is no instance in the story.
Thus your code is meaningless; I can't even imagine what you think you're trying to do (and neither, apparently, can the Swift compiler).
Maybe an example from C will help?
A class method is equivalent to a static function from C. It is just a function. An instance method (non-class) is equivalent to a C function that takes an additional (hidden) parameter: the instance which is the context for your method call.
An equivalent from C might look like this:
static void B() {
...
}
void A(Test test) {
...
}
You can't call a() from b() unless you have a Test object instance to pass for the first parameter.
What I mean is, in Swift, when you have a Test instance and you "call a() on it":
let test = Test()
test.a(...)
You are actually doing something like this:
let test = Test()
A(test,...)