OOP - How to create an interface in Reason - oop

Let's say I have the following abstractProductA class with a public method called methodA :
class abstractProductA = {
pub methodA => "name";
};
I would like to create an interface that says function methodA should always return a string. Something similar to
interface abstractProductA {
abstractProductA(): string
}
only in reason, and then have class implement it. Any suggestions are more than welcome. Thank you

What you're really asking for it seems is how to define and use an abstract class, which is called a virtual class in OCaml/Reason:
class virtual virtualProductA = {
pub virtual methodA: string;
};
class abstractProductA = {
inherit virtualProductA;
pub methodA = "name";
};
An interface is more for consumers to abstract away an implementation, and while a virtual class can be used as an interface by itself, since OCaml/Reason objects are structurally typed you can also just specify the object type you need. And of course you can bind it to a name if you like:
type interfaceA = {.
methodA : string
};
let f (p: interfaceA) => Js.log p#methodA;
f (new abstractProductA);

Related

Dart : Why should overriding method's parameter be "wider" than parent's one? (probably topic about Contravariant) Part2

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.

TypeScript function signature in abstract class doesn't need to match interface

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?

OOP - How to create an instance of one type called to another type in Reason

I have two abstract products types:
type abstractProductA = {.
methodA: string
};
type abstractProductB = {.
methodB: int
};
Used to create the following product classes:
class productA1 = {
pub methodA => "This is methodA of ProductA1";
};
class productB1 = {
pub methodB => 1;
};
I would like to call the instance of abstractProductA, as well as abstractProductB in my abstract factory. Something like the following(syntax is off, I know):
type abstractFactory = {.
createProductA: abstractProductA,
createProductB: abstractProductB
};
So that when I create new concreteFactory using the following class:
class concreteFactory1 = {
pub createProductA => (new productA1);
pub createProductB => (new productA1);
};
and constructer:
let g = new concreteFactory1#createProductB;
Js.log (g#methodA);
the compiler should complain that createProductB only takes an int, and not an string(which it currently does not).
Thank you, and any suggestions are more than welcome.
It seems the error should occur where createProductB returns productA1 instead of productB1. In order to achieve that, you'll need to define a virtual class for abstractFactory instead of just an object type, and then have concreteFactory explicitly inherit from it.
class virtual abstractFactory = {
pub virtual createProductA: abstractProductA;
pub virtual createProductB: abstractProductB;
};
class concreteFactory1 = {
inherit abstractFactory;
pub createProductA => (new productB1);
pub createProductB => (new productB1);
};
This will produce the following error on pub createProductA => (new productB1):
This expression has type productB1 but an expression was expected of type abstractProductA The second object type has no method methodB
See the full example here

OO - Reduce boilerplate/forwarding code

Imagine the following: I have a bunch of DTO's that inherit from Foo class
class Foo { }
class FooA : Foo { }
class FooB : Foo { }
class FooX : Foo { }
Than I have one class that have encapsulated all the related logic and orchestration related with Foo data types. I provide a method DoSomethingWithData(Foo data) that do all the logic related to data provided by argument
The method implementation is something like this:
void DoSomething(Foo data)
{
if (data is FooA)
DoSomethingWithFooA((FooA) data);
if (data is FooB)
DoSomethingWithFooB((FooA)data);
if (data is FooX)
DoSomethingWithFooC((FooA)data);
}
This is a very simplified example. The advantage of this approach is:
The "Client" invoke always the DoSomething method independently of
the Foo data type
If I add a new type I only have to change the method DoSomething
What i dont like is the downcasting
The alternative is instead of exposing only DoSomething method I expose a method by each Foo data type. The advantage is that we dont have downcast but increases the boilerplate/forwarding code.
What do you prefer? Or do you have other approaches?
In this case, I would approach the problem like this (I will use Java for this example).
In your approach, for every subclass of Foo you have to provide a specific processing logic - as you have shown, and cast the Foo object to its sub-type. Moreover, for every new class that you add, you have to change the DoSomething(Foo f) method.
You can make the Foo class an interface:
public interface Foo{
public void doSomething();
}
Then have your classes implement this interface:
public class FooA iplements Foo {
public void doSomething(){
//Whatever FooA needs to do.
}
}
public class FooB implements Foo {
public void doSomething(){
//Whatever FooB needs to do.
}
}
And so on. Then, the client can call the doSomething() method:
...
Foo fooA = new FooA();
Foo fooB = new FooB();
fooA.doSomething();
fooB.doSomething();
...
This way, you don't have to cast the object at run-time and if you add more classes, you don't have to change your existing code, except the client that has to call the method of a newly added object.

Using class variables within an instance of a class

I'm trying to use Swift to create an instance of a class (the class being the desired type) but it would seem that when I initialize the instance the class var is not applied to the new instance. I'm sure there's an init call or something that I'm missing, so any help would be greatly appriciated.
class Person: NSObject {
private struct personNameStruct { static var _personName: String = "" }
class var personName: String
{
get { return personNameStruct._personName }
set { personNameStruct._personName = newValue }
}
}
var testPerson: Person
testPerson.personName = "Foo" //"'person' does not have a member named 'personName'"
An instance member is referred to through a reference to an instance.
A class member is referred to through a reference to the class.
So, for example:
class Dog {
class var whatDogsSay : String {
return "Woof"
}
func bark() {
println(Dog.whatDogsSay)
}
}
To make a dog bark, make a dog instance and tell it to bark:
let d = Dog()
d.bark()
To find out what dogs say, talk to the dog class:
let s = Dog.whatDogsSay
It works for me in a Playground if you access the personName variable using the class name person, not the instance name: person.personName = "Foo".
This is because a class variable in Swift is similar to a static variable in languages like Java and C#, in that it is shared between all instances of that class. If you just want a property in your class you shouldn't declare it as class var but just var.