Why I can not call super in define_method with overloading method?
The error message is quite descriptive. You need to explicitly pass arguments to super
when you call it inside of define_method
block:
mem[args] = super(*args)
Scala - Why are overloaded methods not called based on runtime class?
Static overload resolution is easy to reason about: for the methods that are applicable, a method is selected as "more specific" just based on the signatures.
However,
scala> Seq((new A(), ShowA), (new B(), ShowB))
res0: Seq[(Base, ShowBase)] = List((A@2b45f918,ShowA$@7ee4acd9), (B@57101ba4,ShowB$@6286d8a3))
in ShowBase
there is no overload.
scala> res0 foreach {
| case (obj: A, showImpl) => println(showImpl.show(obj), obj.getClass.getSimpleName)
| case (obj: B, showImpl) => println(showImpl.show(obj), obj.getClass.getSimpleName)
| }
java.lang.InternalError: Malformed class name
at java.lang.Class.getSimpleName(Class.java:1180)
at $anonfun$1.apply(<console>:17)
at $anonfun$1.apply(<console>:16)
at scala.collection.immutable.List.foreach(List.scala:383)
... 38 elided
Oh yeah, don't use getSimpleName
from Scala.
scala> res0 foreach {
| case (obj: A, showImpl) => println(showImpl.show(obj), obj.getClass)
| case (obj: B, showImpl) => println(showImpl.show(obj), obj.getClass) }
(Base,class $line4.$read$$iw$$iw$A)
(Base,class $line5.$read$$iw$$iw$B)
OTOH,
scala> class ShowBase extends Show[Base] {
| override def show(obj: Base): String = "Base"
| def show(a: A) = "A" ; def show(b: B) = "B" }
defined class ShowBase
scala> Seq((new A(), new ShowBase), (new B(), new ShowBase))
res3: Seq[(Base, ShowBase)] = List((A@15c3e01a,ShowBase@6eadd61f), (B@56c4c5fd,ShowBase@10a2918c))
scala> res3 foreach {
| case (obj: A, showImpl) => println(showImpl.show(obj), obj.getClass)
| case (obj: B, showImpl) => println(showImpl.show(obj), obj.getClass) }
(A,class $line4.$read$$iw$$iw$A)
(B,class $line5.$read$$iw$$iw$B)
It's easy to imagine a macro that generates the partial function for a given interface with an overloaded method show
.
Another idea, not necessarily a great one, is to let the compiler do the selection at runtime.
This is currently awkward to demonstrate in REPL. You have to import any symbols you want to use from the objects that litter your REPL history. See the issue.
scala> def imps = $intp.definedSymbolList map (s => $intp.global.exitingTyper { s.fullName }) mkString ("import ", "\nimport ", "\n")
imps: String
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
res15: Any = A
Hey, it worked!
Or, go into power mode, which sets the current phase at typer and gives you intp
without the funky dollar sign. Because do we really need more dollars?
scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'. **
** scala.tools.nsc._ has been imported **
** global._, definitions._ also imported **
** Try :help, :vals, power.<tab> **
scala> def imps = intp.definedSymbolList map (_.fullName) mkString ("import ", "\nimport ", "\n")
imps: String
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
res17: Any = A
If you want to see your unsanitized imports:
scala> intp.isettings.unwrapStrings = false
intp.isettings.unwrapStrings: Boolean = false
scala> imps
res11: String =
"import $line2.$read.$iw.$iw.$intp
import $line3.$read.$iw.$iw.Base
import $line3.$read.$iw.$iw.A
import $line3.$read.$iw.$iw.B
import $line4.$read.$iw.$iw.Show
import $line5.$read.$iw.$iw.ShowA
[snip]
Once more:
scala> abstract class Base ; class A extends Base ; class B extends Base
defined class Base
defined class A
defined class B
scala> trait Show[T <: Base] { def show(obj: T): String }
defined trait Show
scala> class ShowBase extends Show[Base] { override def show(obj: Base): String = "Base" }
defined class ShowBase
scala> object ShowA extends ShowBase { def show(obj: A): String = "A" }
defined object ShowA
scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
** :phase has been set to 'typer'. **
** scala.tools.nsc._ has been imported **
** global._, definitions._ also imported **
** Try :help, :vals, power.<tab> **
scala> def imps = intp.definedSymbolList map (_.fullName) mkString ("import ", "\nimport ", "\n")
imps: String
scala> import tools.reflect._
import tools.reflect._
scala> val tb = reflect.runtime.currentMirror.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@24e15d95
Did I mention the import mechanism is awkward?
scala> val a = new A
a: A = A@1e5b2860
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
res0: Any = A
scala> ShowA show (a: Base)
res1: String = Base
scala> tb.eval(tb.parse(s"$imps ; ShowA show (a: Base)"))
res2: Any = Base
scala> val a: Base = new A
a: Base = A@7e3a93ce
scala> tb.eval(tb.parse(s"$imps ; ShowA show a"))
scala.tools.reflect.ToolBoxError: reflective compilation has failed:
reference to a is ambiguous;
it is imported twice in the same scope by
import a
and import a
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.throwIfErrors(ToolBoxFactory.scala:315)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.wrapInPackageAndCompile(ToolBoxFactory.scala:197)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.compile(ToolBoxFactory.scala:251)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile$2.apply(ToolBoxFactory.scala:428)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile$2.apply(ToolBoxFactory.scala:421)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.liftedTree2$1(ToolBoxFactory.scala:354)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.apply(ToolBoxFactory.scala:354)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.compile(ToolBoxFactory.scala:421)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.eval(ToolBoxFactory.scala:443)
... 37 elided
So, if you decide what type you want to select on:
scala> val x: Base = new A
x: Base = A@2647e550
scala> tb.eval(tb.parse(s"$imps ; ShowA show x"))
res4: Any = Base
scala> tb.eval(tb.parse(s"$imps ; ShowA show (x.asInstanceOf[A])"))
res5: Any = A
Implicit argument passing of super from method defined by define_method() is not supported
The super
above passed all parameters (see this recent question).
As the error message states, you must here "specify all arguments explicitly". Replace super
with super(label, *args)
.
Overload method with subclasses as parameters but have the method called as the superclass
Yes instanceof and getclass would make your class dependent upon specific types and using such practices are not too good.
But by having methods accepting Dog
or Cat
you again end up depending upon the concrete specific implementation.
Better way is Define method in Animal
interface performAction()
. Provide implementation in both Dog
and Cat
. Now iterate your List of Animals and just invoke performAction()
and polymorphically as per actual instance either Dog or Cat implemented method would be called. Later even if there is another implementation of Animal added in code you need not modify your code.
This way you would be having Dog related logic in Dog class, Cat related logic in Cat class and not in any outside different class. This will help in respecting OCP and SRP (Open close and Single Responsibility principles).
Also in case you wish to perform behavior later and your case is such that you know your implementations are fixed and want the using code to inject behavior later then I would recommend Visitor
pattern, but still I feel this should not be abused, (design pattern are often not used but abused) sometime we force a pattern when not needed. Visitor pattern uses polymorphic to dispatch the first call to specific instance from where second dispatch calls the overloaded methods in class implementing the Visitor interface. (name can be different, I have mentioned Visitor to imply class implementing the concept of visitor) . Go for Visitor pattern like implementation only if needed and normal above polymorphic based approach do not fit the situation.
Is parameter's default value still valid in sub class?
Yes, default parameters are inherited automatically by subclasses. In invoking a.print()
, "abc"
is passed as the str
parameter.
See section on overriding: https://docs.scala-lang.org/sips/named-and-default-arguments.html
Can a method in sub class overloading a method in super class?
Taking a more formal approach, the Java Language Specification for Java 7 states:
If two methods of a class (whether both declared in the same class, or both inherited by a class, or one declared and one inherited) have the same name but signatures that are not override-equivalent, then the method name is said to be overloaded.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.9
I would point your friend to this link.
So, in short, in your example, the hello method is indeed overloaded.
Declaring abstract method in TypeScript
The name
property is marked as protected
. This was added in TypeScript 1.3 and is now firmly established.
The makeSound
method is marked as abstract
, as is the class. You cannot directly instantiate an Animal
now, because it is abstract. This is part of TypeScript 1.6, which is now officially live.
abstract class Animal {
constructor(protected name: string) { }
abstract makeSound(input : string) : string;
move(meters) {
alert(this.name + " moved " + meters + "m.");
}
}
class Snake extends Animal {
constructor(name: string) { super(name); }
makeSound(input : string) : string {
return "sssss"+input;
}
move() {
alert("Slithering...");
super.move(5);
}
}
The old way of mimicking an abstract method was to throw an error if anyone used it. You shouldn't need to do this any more once TypeScript 1.6 lands in your project:
class Animal {
constructor(public name) { }
makeSound(input : string) : string {
throw new Error('This method is abstract');
}
move(meters) {
alert(this.name + " moved " + meters + "m.");
}
}
class Snake extends Animal {
constructor(name) { super(name); }
makeSound(input : string) : string {
return "sssss"+input;
}
move() {
alert("Slithering...");
super.move(5);
}
}
How to define method to act as decorator for other methods inside the same class in Python?
I managed to wrap my head around this problem, but at the end I simply choose to extract _write
out class to as regular decorator function.
This solution breaks many rules of The Zen of Python, if there's better solution I'll accept it:
import pathlib
import json
DATABASE_PATH = pathlib.Path('db.json')
class Database:
def __init__(self):
self.data = dict()
def _write(fn):
def decorator(self, **kwargs):
_response = fn(self, **kwargs)
with DATABASE_PATH.open(mode='w', encoding='utf-8') as _db:
json.dump(self.data, _db, indent=4)
return _response
return decorator
@_write
def insert(self, **kwargs):
if all(k for k in kwargs if k in ('name', 'surname')): # Insert if contains all values.
self.data.update(**kwargs)
return True
return False # Insert failed.
if __name__ == '__main__':
db = Database()
db.insert(name='Dummy-Name', surname='Dummy-Surname')
Related Topics
No Such File to Load Bundler Error for Rails 3
How to Create Md5 Hash with Hmac Module in Ruby
How to Use Ruby Metaprogramming to Add Callbacks to a Rails Model
How to Get a HTML Table Row with Capybara
Scientific Programming with Ruby
How to Use Ajax Send Data to Controller in Ruby on Rails
Ruby: Creating a Hash Key and Value from a Variable in Ruby
Set the Display Precision of a Float in Ruby
How to Get Ruby to Parse Time as If It Were in a Different Time Zone
How to Remove Repeated Spaces in a String
Strong Parameters Require Multiple
How to Use Truly Local Variables in Ruby Proc/Lambda
Multiple Blogs in Single Jekyll Website