Forwarding and non-forwarding calls in late static binding (PHP 5.3) - php-5.3

<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
?>
given below is the output:
A
C
C
can anyone evaluate tell how that output has been produced?

The result from the first line in test() "A" does not leverage Late Static Binding, since you are, in all cases, directly calling the class "A"'s implementation of foo (technically it is LSB, but static is bound to A). The second and third lines demonstrate expected behavior with the static keyword, the chain of inheritance does not matter, static refers to the called class. So even though you are calling parent::foo() from B, that implementation used LSB where static keyword resolves to the called class, which is C. The same happens with self::foo().

Related

Getting type of another generic type from Dart type parameter

I would like to make a generic class which only accepts Lists as a type parameter. But I also want the type parameter of the List. Something like this:
class MyClass<L extends List<T>> {
T foo() {
// ....
}
}
The problem is that that does not work. T is not found. But this does:
class MyClass<L extends List<T>, T> {
T foo() {
// ....
}
}
My only issue with this is that I have to always pass in the extra parameter T which should be inferred from the List type.
var instance = MyClass<List<int>>();
var instance = MyClass<List<int>, int>(); // Extra int kind of redundant
Is there any workaround to this?
The solution is similar to the one provided in this question (the same problem, but in Java): basically, you can't do that in Dart. What you can do is
create a new subclass:
class MyClass2<T> extends MyClass<List<T>, T> { ... }
or
create a factory method:
class MyClass<L extends List<T>, T> {
static MyClass<List<T>, T> fromList<T>(List<T> list) {
return MyClass(...);
}
}

How to call a second ancestor method in Dart

Is it possible to call a second ancestor method in dart? something like super.super.hello()? If it's possible, how can it be written?
class A {
void hello() {
print('A');
}
}
class B extends A {
#override
void hello() {
print('B');
}
}
class C extends B {
#override
void hello() {
// How to call the hello() implemented in the class A here?
}
}
void main() {
var c = C();
c.hello();
}
It's not possible.
The reason it's not possible is that it breaks abstraction.
When you look at class C extend B, all you need to know about B is which signatures its members has and which interfaces it implements. As long as that stays effectively the same, your valid code will keep working.
Consider what would happen if the author of B decided to make themselves a helper base-class:
abstract class _BaseB extends A {
String get _myName;
#override
void hello() {
print(_myName);
}
}
class B extends _BaseB {
#override
String get _myName => "B";
}
That's a perfectly valid refactoring. The resulting class B has all the same members and implements all the same interfaces (and also _BaseB, but it's private so nobody can see that).
The C class above would keep working if all it does is to call super.hello(). If it had a way to ask for super.super.hello(), that might no longer be valid.
Similarly if the B class was changed to:
class B implements A {
#override
void hello() {
print("B");
}
}
(changing extends to implements), then all methods of B works the same as before and it implements the same interfaces. Again, there is no visible differences to the users of the B class.
But if you could call something like A.super.hello() to reach the A class's hello method, then that would now break because that method isn't in the B class at all.
So, by restricting super.hello() to only call methods on the precise class you write as the superclass, you are prevented from introducing dependencies on the implementation of B, dependencies which would make otherwise valid refactorings into breaking changes.

How Inheritance works with mixins in dart

I have the following code:
class A {
void m() {
print("hello");
}
}
mixin B {
void m() {
print("mixin class b");
}
}
class C extends A with B {
void m() {
print("m of c");
super.m();
}
}
void main() {
C cc = C();
cc.m();
}
Here when I write super.m() it is referring to the mixin class rather than m() of class A, why? Which exactly is its superclass referenced by super.
How can I then call m() of class A from C?
I don't think it is possible to get the m method on A in your example. The reason is by using mixins you are telling the compiler you want to extend A but please insert all methods from B even if one of the methods overrides an existing one. So after compile, the compiled class of C ends up not even containing A.m.
There are some details about this behavior in this older article and with some explanation about why this is the case: https://medium.com/flutter-community/https-medium-com-shubhamhackzz-dart-for-flutter-mixins-in-dart-f8bb10a3d341

How to capture the generic type of a generic constraint?

Consider the following generic class:
class Foo<T extends Bar<dynamic>> {}
How can I obtain the generic argument of Bar at compile time?
I would expect the following code to print int, but it prints dynamic:
class Bar<T> {}
class Foo<T extends Bar<dynamic>> {
Foo(this.value) {
_debugBarType(value);
}
final T value;
void _debugBarType<A>(Bar<A> value) {
print(A);
}
}
void main() {
Foo<Bar<int>>(Bar());
}
I know I could do:
class Foo<A, Bar<A>> {}
But I would like to define the Foo class using a single generic parameter instead of two.
This is currently not possible to do on any class.
There's currently a pending feature request on Dart to support such use-case: https://github.com/dart-lang/language/issues/620
It's worth noting that there's a workaround if you can add a method on the class concerned.
For example, say you have a generic class Model<T>:
class Model<T> {
T value;
}
Then you can add a "capture" method as such:
class Model<T> {
T value;
R capture<T>(void cb<P>(P value)) => cb<T>(value);
}
This then allows you to write:
void someFunction<T extends Model<dynamic>>(T model) {
model.capture(<P>(value) {
// `P` will be the captured type instead of `dynamic`
});
}

Creating an interface for construction

A few times now I've run into a use case where I need to define an interface for how classes construct themselves. One such example could be if I want to make an Interface Class that defines the interface by which objects can serialize and unserialize themselves (for input into a database, to be sent as JSON, etc). You might write something like this:
abstract class Serializable {
String serialize();
Serializable unserialize(String serializedString);
}
But now you have a problem, as serialize() is properly an instance method, and unserialize() should instead be a static method (which isn't inheritable or enforced by the Interface) or a constructor (which also isn't inheritable).
This leaves a state where classes that impliment the Serializable interface are required to define a serialize() method, but there is no way to require those classes to define a static unserialize() method or Foo.fromSerializedString() constructor.
If you make unserialize() an instance method, then unserializing an implementing class Foo would look like:
Foo foo = new Foo();
foo = foo.unserialize(serializedString);
which is rather cumbersome and ugly.
The only other option I can think of is to add a comment in the Serializable interface asking nicely that implementing classes define the appropriate static method or constructor, but this is obviously prone to error if a developer misses it and also hurts code completion.
So, is there a better way to do this? Is there some pattern by which you can have an interface which forces implementing classes to define a way to construct themselves, or something that gives that general effect?
You will have to use instance methods if you want the inheritance guarantees. You can do a bit nicer than manual instantiation though, by using reflection.
abstract class Serializable {
static Serializable fromSerializedString(Type type, String serializedString) {
ClassMirror cm = reflectClass(type);
InstanceMirror im = cm.newInstance(const Symbol(''), []);
var obj = im.reflectee;
obj.unserialize(serializedString);
return obj;
}
String serialize();
void unserialize(String serializedString);
}
Now if someone implements Serializable they will be forced to provide an unserialize method:
class Foo implements Serializable {
#override
String serialize() {
// TODO: implement serialize
}
#override
void unserialize(String string) {
// TODO: implement unserialize
}
}
You can get an instance like so:
var foo = Serializable.fromSerializedString(Foo, 'someSerializedString');
This might be a bit prettier and natural than the manual method, but keep in mind that it uses reflection with all the problems that can entail.
If you decide to go with a static method and a warning comment instead, it might be helpful to also provide a custom Transformer that scans through all classes implementing Serializable and warn the user or stops the build if any don't have a corresponding static unserialize method or constructor (similar to how Polymer does things). This obviously wouldn't provide the instant feedback the an editor could with instance methods, but would be more visible than a simple comment in the docs.
I think this example is a more Dart-like way to implement the encoding and decoding. In practice I don't think "enforcing" the decode signature will actually help catch bugs, or improve code quality. If you need to make the decoder types pluggable then you can make the decoders map configurable.
const Map<String,Function> _decoders = const {
'foo': Foo.decode,
'bar': Bar.decode
};
Object decode(String s) {
var obj = JSON.decode(s);
var decoder = _decoders[obj['type']];
return decoder(s);
}
abstract class Encodable {
abstract String encode();
}
class Foo implements Encodable {
encode() { .. }
static Foo decode(String s) { .. }
}
class Bar implements Encodable {
encode() { .. }
static Foo decode(String s) { .. }
}
main() {
var foo = decode('{"type": "foo", "i": 42}');
var bar = decode('{"type": "bar", "k": 43}');
}
A possible pattern I've come up with is to create a Factory class that utilize instance methods in a slightly less awkward way. Something like follows:
typedef Constructable ConstructorFunction();
abstract class Constructable {
ConstructorFunction constructor;
}
abstract class Serializable {
String serialize();
Serializable unserialize(String serializedString);
}
abstract class SerializableModel implements Serializable, Constructable {
}
abstract class ModelFactory extends Model {
factory ModelFactory(ConstructorFunction constructor) {
return constructor();
}
factory ModelFactory.fromSerializedString(ConstructorFunction constructor, String serializedString) {
Serializable object = constructor();
return object.unserialize(serializedString);
}
}
and finally a concrete implementation:
class Foo extends SerializableModel {
//required by Constructable interface
ConstructorFunction constructor = () => new Foo();
//required by Serializable interface
String serialize() => "I'm a serialized string!";
Foo unserialize(String serializedString) {
Foo foo = new Foo();
//do unserialization work here to populate foo
return foo;
};
}
and now Foo (or anything that extends SerializableModel can be constructed with
Foo foo = new ModelFactory.fromSerializedString(Foo.constructor, serializedString);
The result of all this is that it enforces that every concrete class has a method which can create a new instance of itself from a serialized string, and there is also a common interface which allows that method to be called from a static context. It's still creating an extra object whose whole purpose is to switch from static to instance context, and then is thrown away, and there is a lot of other overhead as well, but at least all that ugliness is hidden from the user. Still, I'm not yet convinced that this is at all the best way to achieve this.
I suggest you define the unserialize function as named constructor like so:
abstract class Serializable<T> {
String serialize();
Serializable.unserialize(String serializedString);
}
This eliminates the need of static methods.
A possible implementation could look like this:
import 'dart:convert';
class JsonMap implements Serializable<JsonMap> {
Map map = {};
JsonMap() {
}
String serialize() {
return JSON.encode(map);
}
JsonMap.unserialize(String serializedString) {
this.map = JSON.decode(serializedString);
}
}
You can (de)serialize like so:
JsonMap m = new JsonMap();
m.map = { 'test': 1 };
print(m.serialize());
JsonMap n = new JsonMap.unserialize('{"hello": 1}');
print(n.map);
While testing this, I noticed that Dart will not throw any errors at you if you dont actually implement the methods that your class promises to implement with implements. This might just be a hicc-up with my local Dart, though.

Resources