Given a class defined in an external JS library (let's call it Foo) then I'd like to extend in F#
type bar() =
inherits Foo
...
However I can' only find examples of how to integrate with functions
and
[<Import("Foo", from="my-module")>]
let Foo = JsNative
will of course not let me derive Bar from Foo. So how Do I do that
The Import attribute can be used on a type declaration. e.g.
[<Import("Foo", from="my-module")>]
type Foo() =
class
end
type Bar() =
inherit Foo()
You can then also include signatures for the members of the class. It's instructive to look at examples of imports like the Fable React declarations: https://github.com/fable-compiler/fable-react/blob/master/src/Fable.React/Fable.Import.React.fs
Related
Say I have the abstract class A
abstract class A {
A.someConstructor(Foo foo);
}
and all subclasses of A should then implement such constructor:
class B extends A {
#override
B.someConstructor(Foo foo) {
// ...
}
}
So basically what I want is some kind of abstract constructors.
Is there any way of achieving this (of course the above code does not work) or do I need a normal abstract method which then creates the object and sets its properties?
EDIT: Ok so it looks like the only way to create at least a similar behaviour would be something like this:
abstract class A {
A.someConstructor(Object foo);
}
class B extends A {
B.someConstructor(Object foo) : super.someConstructor(foo) {
// ...
}
}
This isn't exactly useful, and after some thinking about my problem I realized that in fact my original goal itself is not really neccessary, so this questions is now answered.
You want to enforce a pattern on the constructors of subclasses. The Dart language has no support for doing that.
Dart has types and interfaces which can be used to restrict values and class instance members.
If a class implements an interface, then its instance members must satisfy the signatures declared by the super-interface. This restricts instance members.
If a variable has a type, for example a function type, then you can only assign values of that type to it. This restricts values. Because a class is a subtype of its interfaces, the subclass restriction means that class typed variables can be used safely (the subtype can be used as its supertype because it has a compatible interface).
There is no way to restrict static members or constructors of classes, or members of libraries, because there is no way to abstract over them. You always have to refer directly to them by their precise name, so there is no need for them to match a particular pattern.
(Which may explain why you found the goal not necessary too).
In this situation, your subclasses must call the A.someConstructor constructor, but they are free to choose the signature of their own constructors. They can do:
class B extends A {
B.someConstructor(Object foo) : super.someConstructor(foo);
}
// or
class C extends A {
C.differentName(Object foo) : super.someConstructor(foo);
}
// or even
class D extends A {
D() : super.someConstructor(new Object());
}
Constructors aren’t inherited
Subclasses don’t inherit constructors from their superclass. A
subclass that declares no constructors has only the default (no
argument, no name) constructor.
Source
I'm working on a project that uses the lua middleclass library. My experiments show that if a class includes a mixin that has a function with the same name as a class function, then calling that function on an instance of the class will call the class function, not the mixin function.
But I couldn't work out why by reading the middleclass code. Is the behaviour guaranteed, or dependent on some call or include order?
EDIT: added minimal code below. Can I rely on myFoo:show() displaying 'Foo'?
class = require('middleclass')
-- this is a middleclass mixin, not a class
Bar = {}
function Bar:show()
print("Bar")
end
-- class Foo implements 'show', and includes
-- the mixin which also implements 'show'
Foo = class('Foo')
Foo:include(Bar)
function Foo:show()
print("Foo")
end
-- class LittleFoo does not implement 'show',
-- but includes the mixin which implements 'show'
LittleFoo = class('LittleFoo')
LittleFoo:include(Bar)
-- program
myFoo = Foo:new()
myLittleFoo = LittleFoo:new()
myFoo:show() -- prints 'Foo'
myLittleFoo:show() -- prints 'Bar'
It is expected behavior, you inherit method show from parent Bar, but you have other implementation in your class. Is common standard in object programing.
It is not in middleclass code, when you do Foo:include(Bar) you have copy of method list (by references) from Bar, but when you implement method Foo:show() ... end, then you rewrite this method, but only for Foo, so in Bar you have old method, and when you inherit it to myLittleFoo, you inherit old version.
I wonder if there is the possibility to dynamically extend a class, I'm new to Dart and I'm looking for something like this (please forget about the ${whatever} is just for illustration purposes):
class MyClass extends ${otherClass}
and let's say I'm trying to instantiate it from another function:
var myDinamic = new myClass<otherClass>
Hope this makes sense and thanks in advance!
In short: No.
Dart requires all classes to have a single superclass. What you are asking for is having a single class that changes its superclass per instance. That's not really a single class - it's impossible to say which members that class has because it is really a different class for choice of superclass.
That a class extends another class can only be defined statically but not at runtime. The closest to that is probably configuring types with generic type arguments.
See also
- https://www.dartlang.org/docs/dart-up-and-running/ch02.html#generics
- http://blog.sethladd.com/2012/01/generics-in-dart-or-why-javascript.html
abstract class SomeInterface {}
class A implements SomeInterface {}
class B implements SomeInterface {}
class C<T extends SomeInterface> {
T doSomething(T arg) { return arg; }
}
main() {
new C<A>();
new C<B>();
// does NOT work
// var t = A;
// new C<t>();
}
but type arguments also need to defined statically. You can't use a variable as generic type argument.
F# accepts the following:
type Abc =
member this.A = 10
Since no parameter-list was supplied, there is no default constructor. Can a constructor be added to Abc? If not, what can be done with Abc?
I can't think of many uses for this, but two things you can do are
inherit from it, albeit derived types must not be instantiable either
extend it with static members (although this is better achieved with modules, which can also be extended)
type Abc =
member this.A = 10
[<Class>]
type Def =
inherit Abc
type Abc with
static member Foo() = ()
In C#, Code Contracts for an interface or abstract class are defined in a "contract class" which must be marked abstract and have a private constructor (i.e. it's non-instantiable). This, in my opinion, is a better way of accomplishing that. But C# doesn't support constructor-less classes.
I'm coming from C#/F#/Haskell so I'm trying to come up with solutions to programming problems I'm used to solving with types.
class A where T : new() in C#, this is mainly so I can do new T() somewhere. This creates a malformed type error in Dart. Is there a reasonably idiomatic way to solve this? Perhaps with factories?
I did some experiments with mixins, in the case of name conflicts for inherited mixin members, the last mixin wins. So for the following:
abstract class mixA { void foo(); }
abstract class mixB { void foo(); }
class C extends Object with mixA, mixB {}
new C().foo();
this would end up calling mixB.foo() whereas
class C extends Object with mixB, mixA {}
would end up calling mixA.foo()
Is there anyway to access the members of the hidden mixins?
Suppose I mix 2 mixins with a field of the same name. Does the subclass instance have 2 fields at runtime (just 1 is inaccessible) or is the object like a dictionary and there is only 1 slot for each name?
1 is not possible. You can't call new on a generic type (or variable for that matter). The most common workaround is to create a closure that allocates the object instead.
The answers for 2 fall out of the fact that Mixins can be seen as super-classes: A extends Object with B, C is basically equivalent to:
class B' extends Object { <copy over code inside B> }
class C' extends B' { <copy over code inside C> }
class D extends C' { ... }
With this in mind:
no. there is no way to access hidden super elements.
yes. you would end up with multiple fields.
Small note: the <copy over code inside X> part is not completely correct since that would change the library-scope. Code from mixin B is conceptually in the library the mixin is declared in.