I'm overriding a protected function in a subclass.
Let's say I have two classes, Apple and Fruit.
I have all variables in place, this is just a simplified version.
class FruitBasket
protected function getRandom():Fruit
{
// return random piece of fruit
}
class AppleBasket extends FruitBasket
protected override function getRandom():Apple
{
// return random apple
}
class Fruit
class Apple extends Fruit
Example is trivial. The problem is that the type of the getRandom function depends on its own type. One returns an apple, the other returns a fruit.
Of course I get errors about override and coercion.
I've tried returning a Fruit instead of an Apple, but then the object is not an apple, therefore it has no Apple-specific properties.
The problem is in ducktyping. There's a third class I cannot change, that executes the getRandom() function on each object, and I need the Apples to be something slightly different.
How can I override the getRandom function in Apple, so that it returns apples, rather than fruit?
This is a circle-ellipse problem. I would simply not override the function; rather I would rename the function to be more specific. So rename it to getRandomApple() in AppleBasket. Your semantics are getting a little muddy so I would make things separate and clearer.
It's too bad you can't change the function name in FruitBasket, because I would change that to getRandomFruit() to make the semantics clearer.
The equivalent to duck typing in AS3 would be the "*" or "Object" type.
Related
Even though I am familiar with singleton, Dart's factory is confusing. I have seen an existing question, but the only thing I got from the answer is that the name can be whatever identifier that starts with an _. Even though the person had asked why it should be called, the answer does not seem to be explaining that.
If I comment out the Dog._internal(); line, I get Method not found: 'Dog._internal'. It looks like calling a method, but is it like C's function prototype? But it has no return type. Can someone explain the Dog._internal(); line to me?
class Dog
{
static final Dog dog = Dog._internal();
//Dog._internal();
factory Dog()
{
return dog;
}
}
There are multiple concepts going on so lets go through the example:
factory Dog()
{
return dog;
}
This defines a factory constructor. Factory constructors are much like normal static methods but must always return an object which are compatible with the type of which the factory constructor is part of. In our example the factory constructor must return a Dog object.
It is not a constructor in that sense that we already have created a object when we enter this method. Again, it can be compared to static Dog Dog() but is allowed to override the default constructor. So we must create the object manually and return it.
This allows us to control the behavior of when objects are created and in our case allows us to have a singleton pattern so when somebody are trying to create an instance of Dog they will always get the same object.
Dog._internal();
This is called a named constructor. Constructors in Dart can have given names which makes it easier to distinguish different constructors. But also because Dart does not allows us to override methods with different number of parameters.
Also, because of the name starting with _ it means this constructor is marked private and cannot be used outside of the library it is part of. So if your code is part of a library, the code importing your library are not allowed to call your private constructor.
This is again a nifty trick to allow us to make a singleton since we don't want other than our own code to create a new instance (which are the only instance we want to create).
static final Dog dog = Dog._internal();
This is essential creating the singleton. The reason for this is that static variables in Dart are lazy-evaluated so the value dog does not really have any value before it is called. After first call, the value are "cached" so Dog._internal(7) are only called once as long our application (or more specific, our isoleate instance) are running.
I would properly call the variable _instance or _dog so it is also private.
Dog.foo(); defines a named constructor named foo that takes no arguments and has no body. It's equivalent to Dog.foo() {}. Similarly, Dog._internal(); defines a named constructor named _internal. This would be more obvious if the constructor took arguments and did work, for example:
class Dog {
static final Dog dog = Dog._internal(7);
Dog._internal(this.years) {
registerAnimal(this);
}
factory Dog() {
return dog;
}
int years;
}
A common question, specifically since Dart 2, is if it is possible to require some or all generic type arguments on some or all types - for example List<int> instead of List or MyType<Foo> instead of MyType.
It's not always clear what the intention is though - i.e. is this a matter of style (you/your team likes to see the types), to prevent bugs (omitting type arguments seems to cause more bugs for you/your team), or as a matter of contract (your library expects a type argument).
For example, on dart-misc, a user writes:
Basically, if I have this:
abstract class Mixin<T> {}
I don't have to specify the type:
// Works class Cls extends Object with Mixin<int> {} // ...also works
class Cls extends Object with Mixin {}
Is there some way to make the second one not allowed?
Strictly speaking, yes, and no.
If you want to enforce that type arguments are always used in your own projects (instead of relying on type inference or defaults), you can use optional linter rules such as always_specify_types. Do note this rule violates the official Dart style guide's recommendation of AVOID redundant type arguments on generic invocations in many cases.
If you want to enforce that generic type arguments are always used when the default would be confusing - such as List implicitly meaning List<dynamic>, no such lint exists yet - though we plan on adding this as a mode of the analyzer: https://github.com/dart-lang/sdk/issues/33119.
Both of the above recommendations will help yourself, but if you are creating a library for others to use, you might be asking if you can require a type argument to use your class. For example, from above:
abstract class Mixin<T> {}
abstract class Class extends Object with Mixin {}
The first thing you could do is add a default bounds to T:
// If T is omitted/not inferred, it defaults to num, not dynamic.
abstract class Mixin<T extends num> {}
If you want to allow anything but want to make it difficult to use your class/mixin when T is dynamic you could choose a different default bound, for example Object, or even better I recommend void:
In practice, I use void to mean “anything and I don’t care about the elements”
abstract class Mixin<T extends void> {
T value;
}
class Class extends Mixin {}
void main() {
var c = Class();
// Compile-time error: 'oops' isn't defined for the class 'void'.
c.value.oops();
}
(You could also use Object for this purpose)
If this is a class under your control, you could add an assertion that prevents the class from being used in a way you don't support or expect. For example:
class AlwaysSpecifyType<T> {
AlwaysSpecifyType() {
assert(T != dynamic);
}
}
Finally, you could write a custom lint or tool to disallow certain generic type arguments from being omitted, but that is likely the most amount of work, and if any of the previous approaches work for you, I'd strongly recommend those!
For example, I'd like to just be able to write:
class Dog {
final String name;
Dog(this.name);
bark() => 'Woof woof said $name';
}
But have #Dog.bark's type definition be () => String.
This previously wasn't possible in Dart 1.x, but I'm hoping type inference can save the day and avoid having to type trivial functions where the return type is inferable (the same as it does for closures today?)
The language team doesn't currently have any plans to do inference on member return types based on their bodies. There are definitely cases like this where it would be nice, but there are other cases (like recursive methods) where it doesn't work.
With inference, we have to balance a few opposing forces:
Having smart inference that handles lots of different cases to alleviate as much typing pain as we can.
Having some explicit type annotations so that things like API boundaries are well-defined. If you change a method body and that changes the inferred return type, now you've made a potentially breaking change to your API.
Having a simple boundary between code that is inferred and code that is not so that users can easily reason about which parts of their code are type safe and which need more attention.
The case you bring up is right at the intersection of those. Personally, I lean towards not inferring. I like my class APIs to be pretty explicitly typed anyway, since I find it makes them easier to read and maintain.
Keep in mind that there are similar cases where inference does come into play:
Dart will infer the return type of an anonymous function based on its body. That makes things like lambdas passed to map() do what you want.
It will infer the return type of a method override from the method it is overriding. You don't need to annotate the return type in Beagle.bark() here:
class Dog {
String bark() => "Bark!";
}
class Beagle extends Dog {
final String name;
Dog(this.name);
bark() => 'Woof woof said $name';
}
Suppose I want my class to do things on attribute access. I can of course do that in setters and getters:
class Foo {
set bar (v) {
// do stuff
}
}
However, if I want to attach the same behavior to multiple attributes, I'd have to explicitly define the same setters and getters for every one of them. (The use case I have in mind is an observable, i.e. a class that knows when its attributes are being changed).
What I'd like to do is something like:
class Foo {
var bar = new AttributeWithAccessBehavior();
}
Python does this with descriptors - what is the closest thing in Dart?
AFAIK there isn't anything with getter/setter syntax that you can reuse.
You could assign a function to a field, that you can access using call notation (), but you have to be careful to call the function instead of overriding the field assignment.
A similar but more powerful alternative are classes that can emulate functions (see https://www.dartlang.org/articles/emulating-functions/)
A class that has a call method can be used like a method.
This is similar to assigned functions mentioned above but in addition you can store state information.
If you implement actual getter/setter you can of course delegate to whatever you want, but that is obviously not what you are looking for.
For the use case you mentioned, there is the observe package.
I have no idea how exactly it solves the problem, but it works quite well.
I just learned in my programming languages class that "contravariant argument types would actually be safe, but they have not been found useful and are hence not supported in practical languages." Even though they are not supported, I am confused as to why something like this example we were given would still be, in theory, "safe":
class Animal {
...
public bool compare(Panda) { ... }
}
class Panda extends Animal {
...
public bool compare(Animal) { ... }
}
From what I understand, problems with subtyping come up when something is done that could cause a loss of specificity. So what if I did this? :
Panda p = new Panda();
Animal a = new Animal
...
p.compare(a);
When I look at this, it seems like panda could (and probably does) have some extra fields in it that a plain animal wouldn't know about. Thus, even if all of their animal-specific data members are the same, a panda can have other stuff that differs. How would that make it okay to compare it to a plain animal? Would it just consider the animal-only stuff and ignore the rest?
In your example you don't use any generic types. You have Panda extending Animal, and it's an example of inheritance and leads to polymorphism which is more or less what you describe. Check the links.
To get contravariance, you need to consider some generic type. I'll use .NET type IComparer`1[T] as an example. With C# syntax (which I'll use rather than Java), we indicate that IComparer is contravariant in T by writing in in the definition:
public interface IComparer<in T>
{
...
}
Suppose I have a method which returns an IComparer`1[Animal] (or IComaparer<Animal>), like:
static IComparer<Animal> CreateAnimalComparer()
{
// code that returns something here
}
Now in C#, it's legal to say:
IComparer<Panda> myPandaComparer = CreateAnimalComparer();
Now, this is because of contravariance. Note that the type IComparer<Animal> does not derive from (or "extend") the type IComparer<Panda>. Instead, Panda derives from Animal, and this leads to the IComparer<Xxxx> being assignable to each other (in the opposite order, hence "contravariance" (not "covariance")).
The reason why it's meaningful to declare a Comparer<> contravariant, is if you have a comparer that can compare two arbitrary animals, and return a signed number indicating which is greater, then that same comparer can also take in two pandas and compare those. For pandas are animals.
So the relation
any Panda is an Animal
(from inheritance) leads to the relation
any IComparer<Animal> is an IComparer<Panda>
(by contravariance).
For an example with covariance, the same relation
any Panda is an Animal
leads to
any IEnumerable<Panda> is an IEnumerable<Animal>
by covariance (IEnumerable<out T>).