I've been learning Scala for web-development for quite some time, and I have stumbled upon a lack of interfaces. Coming from PHP, I used interfaces quite a lot for method-level polymorphism and IoC like this:
interface iAnimal
{
function makeVoice();
}
class Cat implements iAnimal
{
function makeVoice()
{
return "Meow";
}
}
class Dog implements iAnimal
{
function makeVoice()
{
return "Woof!";
}
}
class Box
{
private $_animal;
function __construct(iAnimal $animal)
{
$this->_animal = $animal;
}
function makeSound()
{
echo $this->_animal->makeVoice();
}
}
And so on, and that was an easy way to ensure that anything I passed to the Box object had a makeVoice method that I was calling elsewhere. Now, what I'm curious of, is how do I implement similar functionality with Scala. I tried searching for this, but info is quite scarce. The only answer I found was to use traits, but as far as I know, they are used for concrete implementation, not declaration.
Thanks in advance.
As per other answers, the solution is to use traits :
trait Animal {
def makeVoice(): Unit //no definition, this is abstract!
}
class Cat extends Animal{
def makeVoice(): Unit = "Meow"
}
class Dog extends Animal{
def makeVoice(): Unit = "Woof"
}
class Box(animal:Animal) {
def makeSound() = animal.makeVoice()
}
A trait in Scala will be directly compiled to an interface in Java. If it contains any concrete members then these will be directly copied into any class that inherits from the trait. You can happily use a Scala trait as an interface from Java, but then you don't get the concrete functionality mixed in for you.
However... this is only part of the picture. What we've implemented so far is subtype polymorphism, Scala also allows for ad-hoc polymorphism (a.k.a typeclasses):
// Note: no common supertype needed here
class Cat { ... }
class Dog { ... }
sealed trait MakesVoice[T] {
def makeVoice(): Unit
}
object MakesVoice {
implicit object CatMakesVoice extends MakesVoice[Cat] {
def makeVoice(): Unit = "Meow"
}
implicit object DogMakesVoice extends MakesVoice[Dog] {
def makeVoice(): Unit = "Woof"
}
//helper method, not required, but nice to have
def makesVoice[T](implicit mv: MakesVoice[T]) = mv
}
import MakesVoice._
//context-bound version
class Box[T : MakesVoice] {
//using a helper:
def makeSound() = makesVoice[T].makeVoice()
//direct:
def makeSound() = implicitly(MakesVoice[T]).makeVoice()
}
//using an implicit param
class Box[T](implicit mv : MakesVoice[T]) {
def makeSound() = mv.makeVoice()
}
What's important here is that the MakesVoice type class can be associated with any type regardless of what hierarchies it belongs to. You can even use type classes with primitives or types imported from a 3rd party library that you couldn't possibly retrofit with new interfaces.
Of course, you have parametric polymorphism as well, which you'd probably know better as "generics" :)
Traits are used for both declaration and concrete implementation. Here is a direct translation of your example
trait Animal {
def makeVoice()
}
class Cat extends Animal{
override def makeVoice(): Unit = "Meow"
}
class Dog extends Animal{
override def makeVoice(): Unit = "Woof"
}
class Box(animal:Animal) {
def makeSound()={
animal.makeVoice()
}
}
Additionally, you are able to actually define a concrete implementation directly in the trait which is useful for behaviours shared by members of different class hierarchies:
trait Fish{
def swim()="Swim"
}
class Truit extends Fish
trait Bird{
def fly() = "Fly"
}
class Eagle extends Bird
class Duck extends ???{
def swim=???
def fly=???
}
The duck both swims ans flies, you could define it as such :
trait Swimmer{
def swim
}
trait Fish extends Swimmer{
def swim()="Swim"
}
class Truit extends Fish
trait Bird{
def fly()="Fly"
}
class Eagle extends Bird
class Duck extends Bird with Swimmer
Related
I have generic interface...
interface Parent<T> {
fun function(entity: T): Int
}
And when I implement functionality with some child class...
class Other : Parent<Other> {
override fun function(entity: Other): Int {
return 42
}
}
I'm bothered with the fact that I have to pass the same class type while implementing the interface... I would really like for the interface to be able to detect on which class is attached on its own without me providing the same type again...
I would like code something like this...
class Other : Parent {
override fun function(entity: Other): Int {
return 42
}
}
Is it possible in kotlin to do that in some form?
Not in the general case, but sometimes when a generic is fully constrained by another: https://kotlinlang.org/docs/generics.html#underscore-operator-for-type-arguments
https://dart.dev/guides/language/language-tour#extending-a-class
Argument types must be the same type as (or a supertype of) the
overridden method’s argument types. In the preceding example, the
contrast setter of SmartTelevision changes the argument type from int
to a supertype, num.
I was looking at the above explanation and wondering why the arguments of subtype member methods need to be defined more "widely"(generally) than the original class's one.
https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Function_types
class AnimalShelter {
Animal getAnimalForAdoption() {
// ...
}
void putAnimal(Animal animal) {
//...
}
}
class CatShelter extends AnimalShelter {
//↓ Definitions that are desirable in the commentary
void putAnimal(Object animal) {
// ...
}
//↓Definitions that are not desirable in the commentary
void putAnimal(Cat animal) {
// ...
}
//I can't understand why this definition is risky.
//What specific problems can occur?
}
I think this wikipedia sample code is very easy to understand, so what kind of specific problem (fault) can occur if the argument of the member method of the subtype is defined as a more "narrower"(specific) type?
Even if it is explained in natural language, it will be abstract after all, so it would be very helpful if you could give me a complete working code and an explanation using it.
Let's consider an example where you have a class hierarchy:
Animal
/ \
Mammal Reptile
/ \
Dog Cat
with superclasses (wider types) above subclasses (narrower types).
Now suppose you have classes:
class Base {
void takeObject(Mammal mammal) {
// ...
}
Mammal returnObject() {
// ...
}
}
class Derived extends Base {
// ...
}
The public members of a class specify an interface: a contract to the callers. In this case, the Base class advertises a takeObject method that accepts any Mammal argument. Every instance of a Base class thus is expected to conform to this interface.
Following the Liskov substitution principle, because Derived extends Base, a Derived instance is a Base, and therefore it too must conform to that same Base class interface: its takeObject method also must accept any Mammal argument.
If Derived overrode takeObject to accept only Dog arguments:
class Derived extends Base {
#override
void takeObject(Dog mammal) { // ERROR
// ...
}
}
that would violate the contract from the Base class's interface. Derived's override of takeObject could be invoked with a Cat argument, which should be allowed according to the interface declared by Base. Since this is unsafe, Dart's static type system normally prevents you from doing that. (An exception is if you add the covariant keyword to disable type-safety and indicate that you personally guarantee that Derived.takeObject will never be called with any Mammals that aren't Dogs. If that claim is wrong, you will end up with a runtime error.)
Note that it'd be okay if Derived overrode takeObject to accept an Animal argument instead:
class Derived extends Base {
#override
void takeObject(Animal mammal) { // OK
// ...
}
}
because that would still conform to the contract of Base.takeObject: it's safe to call Derived.takeObject with any Mammal since all Mammals are also Animals.
Note that the behavior for return values is the opposite: it's okay for an overridden method to return a narrower type, but returning a wider type would violate the contract of the Base interface. For example:
class Derived extends Base {
#override
Dog returnObject() { // OK, a `Dog` is a `Mammal`, as required by `Base`
// ...
}
}
but:
class Derived extends Base {
#override
Animal returnObject() { // ERROR: Could return a `Reptile`, which is not a `Mammal`
// ...
}
}
void main(){
Animal a1 = Animal();
Cat c1 = Cat();
Dog d1 = Dog();
AnimalCage ac1 = AnimalCage();
CatCage cc1 = CatCage();
AnimalCage ac2 = CatCage();
ac2.setAnimal(d1);
//cc1.setAnimal(d1);
}
class AnimalCage{
Animal? _animal;
void setAnimal(Animal animal){
print('animals setter');
_animal = animal;
}
}
class CatCage extends AnimalCage{
Cat? _cat;
#override
void setAnimal(covariant Cat animal){
print('cats setter');
_cat = animal;
/*
if(animal is Cat){
_cat = animal;
}else{
print('$animal is not Cat!');
}
*/
}
}
class Animal {}
class Cat extends Animal{}
class Dog extends Animal{}
Unhandled Exception: type 'Dog' is not a subtype of type 'Cat' of 'animal'
In the above code, even if the setAnimal method receives a Dog instance, a compile error does not occur and a runtime error occurs, so making the parameter the same type as the superclass's one and checking the type inside the method is necessary.
I know most of you already know of the animal-cow-grass-food problem
-which states that you have a code like below, that has a type constraint on Cow (which inherits Animal ) to only eat SuitableFood (which inherits Food )
Below is the SCALA representation of the same
class Food
class Grass extends Food
class Cookies extends Food
class Fish extends Food
abstract class Animal {
type SuitableFood <: Food
def eat(food: SuitableFood)
}
class Cow extends Animal {
type SuitableFood = Grass
override def eat(food: SuitableFood) = {}
}
val bessy: Animal = new Cow
bessy eat new Fish
bessy eat new Cookies
I was wondering if similar is possible in KOTLIN or JAVA ?
Not sure what you want to achieve. Restriction for Cow to eat only Grass ?
I think this can be done through generic types.
abstract class Food
open class Grass : Food()
class GreenGrass : Grass()
class Fish : Food()
abstract class Animal<T : Food> {
fun eat(food: T) { ... }
}
class Cow : Animal<Grass>()
class Bear : Animal<Fish>()
class Test {
fun test() {
val cow = Cow()
cow.eat(Grass()) // ok
cow.eat(GreenGrass()) // ok
cow.eat(Fish()) // not ok
val bear = Bear()
bear.eat(Fish()) // ok
bear.eat(Grass()) // not ok
}
}
In the following example, interface IFoo declares a function signature requiring two number arguments. Abstract class BaseFoo implements this interface, but declares the function with a different signature. Finally, concrete class Foo extends BaseFoo and implements BaseFoo's version of the function declaration.
interface IFoo {
func(x: number ): number
}
abstract class BaseFoo implements IFoo {
abstract func(x: number): number
}
class Foo extends BaseFoo {
func() { return -1 } // Does not match interface func declaration
}
let foo: IFoo = new Foo() // Should not be able to instantiate a Foo as an IFoo
let y = foo.func() // Should not be able to call without an argument
console.log(y)
This contrived example illustrates something that happened in real life: I had an existing interface in a codebase. I updated one of it's function's signatures, with the expectation that the compiler would help me find all the classes who would need to be updated. But, no errors.
Why am I allowed to instantiate an abstract class with a function signature that doesn't match the interface?
I would like to run unit tests from the abstract class instead of from the concrete classes that inherit from it. I tried a few things that would not compile:
unittest(this T) { ... }
abstract class Parent(this T) : GrandParent
{
...
unittest
{
T x = new T();
x.something = true;
assert(x.something == true);
}
...
}
Is there something else I can do to de-duplicate the thousands of lines of unit tests that are otherwise going to exist for each child class?
If you're happy with a base class that's specialized (and thus duplicated) for each subclass:
abstract class Base(T) {
static assert(is(T : typeof(this)), "Tried to instantiate "~typeof(this).stringof~" with type parameter "~T.stringof);
unittest {
import std.stdio : writeln;
auto a = new T();
writeln(a.s);
}
}
class Derived : Base!Derived {
string s() {
return "a";
}
}
Instead of the static assert, I'd have preferred to have a template constraint on Base, but sadly this doesn't work (when the constraint is tested, we don't yet know if Derived inherits from Base!Derived, since that only happens after the constraint has passed, of course).
This pattern is known in C++ as Curiously Recurring Template Pattern (CRTP).