Mixins in Dart: How To Use Them - dart

So I'm trying to create a simple little program where I utilize mixins. I want to represent a bookstore and have two products (books, bags)..but I want the abstract class up top (Com) to define methods that can be applied to all products (objects) without changing the individual classes. However, I have no idea how to implement this. The method can be as simple as tracking if a certain book is in the bookstore.
Here is my current code:
abstract class Com {
not sure not sure
}
class Product extends Object with Com {
String name;
double price;
Product(this.name, this.price);
}
class Bag extends Product {
String typeofb;
Bag(name, price, this.typeofb) :super(name, price);
}
class Book extends Product {
String author;
String title;
Book(name, price, this.author, this.title):super(name, price);
}
void main() {
var b = new Book('Best Book Ever', 29.99,'Ed Baller & Eleanor Bigwig','Best
Book Ever');
}

A Dart mixin is currently just a bag of members that you can copy on the top of another class definitions.
It's similar to implementation inheritance (extends) except that you extend the superclass, but extend with the mixin. Since you can only have one super-class, mixins allows you a different (and much more restricted) way to share implementation that doesn't require the super-class to know about your methods.
What you describe here sounds like something the can just as well be handled using a common superclass. Just put the methods on Product and let Bag and Book both extend that class. If you don't have any subclass of Product which doesn't need the mixin methods, there is no reason to not include them in the Product class to begin with.
If you do want to use a mixin, you can write something like:
abstract class PriceMixin {
String get sku;
int get price => backend.lookupPriceBySku(sku);
}
abstract class Product {
final String sku;
Product(this.sku);
}
class Book extends Product with PriceMixin {
final String title;
Product(String sku, this.title) : super(sku);
}
class Bag extends Product with PriceMixin {
final String brand;
Product(String sku, this.brand) : super(sku);
}
class Brochure extends Product { // No PriceMixin since brochures are free.
final String name;
Brochure(String sku, this.name) : super(sku);
}

Related

Dart cannot override function in generic class with subclass of generic

I am writing an app which deals with both cryptos and stocks. Because they share many common characteristics such as symbol, price, name etc, I created a base class 'instrument' then subclasses for stock and crypto. I have a generic 'manager' class for both, as loading, saving etc are again very similar. However, there are some functions, such as fetching a current price, that need to be implemented differently, so I have extended my generic manager class and I am trying to override the relevant function, i.e. fetchCurrentPrice() in the example below. Dart complains that
'CryptoManager.fetchCurrentPrice' ('Future Function(Crypto)') isn't a valid override of 'Manager.fetchCurrentPrice' ('Future Function(Instrument)').
I don't understand this, as I have defined as type in the manager, and Crypto extends Instrument, so I am fulfilling this criterion. Any idea where I am going wrong?
abstract class Instrument {
String name = 'Instrument';
double currentPrice = 0.0;
Instrument(this.name);
}
class Crypto extends Instrument {
Crypto(super.name);
String contractAddress = '0xBCCFF3FF6...';
}
abstract class Manager<T extends Instrument> {
List<T> instruments = [];
Future<double> fetchCurrentPrice(T instrument) async {
print('Fetching price for generic instrument');
return 12.80;
}
}
class CryptoManager extends Manager {
// this is causing the issue
#override
Future<double> fetchCurrentPrice(Crypto instrument) async {
print('Fetching price for crypto');
return 12.80;
}
}
void main(List<String> args) {
CryptoManager cryptoManager = CryptoManager();
var btcCrypto = Crypto('BTC');
cryptoManager.fetchCurrentPrice(btcCrypto);
}
Your class CryptoManager needs to extend Manager<Crypto>, not just "some Manager, kinda".
class CryptoManager extends Manager<Crypto>

Restrict Xtext scoping to folder

When having two Xtext models in the same project but in different folders using the same names (ID) for different objects, the scoping does not work how I want it to. How can I restrict the scoping to inside one folder and not the whole project?
Example:
grammar:
Model:
persons+=Person*
greetings+=Greeting*;
Greeting:
'Hello' name=[Person] '!';
Person:
'person' name=ID;
folder structure:
project
|-folder1
|-person1.mydsl
|-folder2
|-greeting.mydsl
|-person2.mydsl
person1.mydsl contains a Person ("Jane"), person2.mydsl also contains a Person ("Jane") and greeting.mydsl contains a Greeting ("Hello Jane!") referencing the person in person1.mydsl instead of the person in person2.mydsl.
The documentation tells me to use the StateBasedContainerManager but I don't understand where and how.
Thanks to #Christian and this I found a solution. So first adding a filter to the DefaultGlobalScopeProvider
public class MyGlobalScopeProvider extends DefaultGlobalScopeProvider {
#Override
public IScope getScope(Resource resource, EReference reference, Predicate<IEObjectDescription> filter) {
filter = new Predicate<IEObjectDescription>() {
#Override
public boolean apply(IEObjectDescription input) {
// implement here
}
};
return super.getScope(resource, reference, filter);
}
}
and then telling my runtime module to use my provider instead
public class MyDslRuntimeModule extends AbstractMyDslRuntimeModule {
#Override
public Class<? extends IGlobalScopeProvider> bindIGlobalScopeProvider() {
return MyGlobalScopeProvider.class;
}
}

Create interface that contains Freezed class signatures so I can called freezed functions on my interfaces

I'm trying to have a base Freezed interface which my app entity interfaces can extend so I can call the freezed functions on the interfaces. I've started the process here which seems to be working so far:
abstract class IUserRegistrationEntity<T> extends FreezedClass<T> {
String get nickName;
String get email;
String get confirmEmail;
String get password;
String get confirmPassword;
}
abstract class FreezedClass<T> {
T get copyWith;
Map<String, dynamic> toJson();
}
freezed class:
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:vepo/domain/user_registration/i_user_registration_entity.dart';
part 'user_registration_entity.freezed.dart';
part 'user_registration_entity.g.dart';
#freezed
abstract class UserRegistrationEntity with _$UserRegistrationEntity {
#Implements.fromString(
'IUserRegistrationEntity<\$UserRegistrationEntityCopyWith<IUserRegistrationEntity>>')
const factory UserRegistrationEntity(
{String nickName,
String email,
String confirmEmail,
String password,
String confirmPassword}) = _IUserRegistrationEntity;
factory UserRegistrationEntity.fromJson(Map<String, dynamic> json) =>
_$UserRegistrationEntityFromJson(json);
}
But now I need to add the fromJson factory constructor to the interface. I think this may be what I'm looking for although I can't really tell how to implement it in my code:
T deserialize<T extends JsonSerializable>(
String json,
T factory(Map<String, dynamic> data),
) {
return factory(jsonDecode(json) as Map<String, dynamic>);
}
You an then call it with:
var myValue = deserialize(jsonString, (x) => MyClass.fromJson(x));
Any help adding the fromJson to my freezed interface would be appreciated.
I've found a way to get the same benefits of programming to an interface or "abstraction" with freezed objects, while still getting to call those freezed functions:
#freezed
abstract class Person with _$Person {
#With(BasicPersonMixin)
const factory Person.basicPerson(
{int? id, String? firstName, String? lastName}) = BasicPerson;
#With(FancyPersonMixin)
const factory Person.fancyPerson({String? firstName, required String extraPropMiddleName, String? lastName}) =
FancyPerson;
factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
const Person._();
void functionThatEveryPersonShares() {
print('I am a person');
}
String greet() {
return 'override me with a mixin or abstract class';
}
}
mixin FancyPersonMixin {
String get extraPropMiddleName {
return 'my default middle name is John`;
}
String greet() {
return 'Salutations!';
}
void specialisedFunctionThatOnlyIHave() {
print('My middle name is $extraPropMiddleName');
}
}
mixin BasicPersonMixin {
String greet() {
return 'Hi.';
}
}
Now we have 2 concrete classes: BasicPerson, and FancyPerson which are both a Person. Now we can program to Person throughout the app, and still call .copyWith and .fromJson and so on and so forth. The different types of Person can vary independently from each other by using mixins and still be used as a Person type. Works with generics etc (from docs - #With.fromString('AdministrativeArea<House>')) but I have kept the example simple for this question to most simply show the benefits. You can also make Person extend another base class.
I've found another way to let you be a bit more abstract than my other answer. Say you're in a highly abstract super-class, so you don't want to work with objects as specific as Person. You want to work with "a base freezed object"; just cast your type to dynamic in brackets and go ahead and use copyWith freely. Sure, it's not typesafe, but it's a worthy option if it allows you to do something in a super-class rather than in every sub-class.
mixin LocalSaveMixin<TEntity extends LocalSaveMixin<TEntity>> on Entity {
LocalRepository<TEntity> get $repository;
Ref? get provider;
TEntity $localFetch() {
return ($repository.$localFetch() as dynamic).copyWith(provider: provider)
as TEntity;
}
TEntity $localSave() {
return $repository.$localSave(entity: this as TEntity);
}
}

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.

ASP.NET MVC 3 views, super classes don't work for subclasses?

I have the following classes -
public abstract class BusinessObject { }
public abstract class Form: BusinessObject { }
public abstract class BillableForm: Form { }
public class MembershipForm: BillableForm { }
public abstract class Dto<T>: where T: BusinessObject { }
public abstract class InboxDto<T>: Dto<T> where T: Form { }
public class MembershipFormDto: InboxDto<MembershipForm> { }
And I have the following views -
membershipform.cshtml:
#model AdminSite.Models.MembershipFormDto
#{
Layout = "~/Views/Inbox/Shared/_LayoutForm.cshtml"
}
_LayoutForm.cshtml:
#model InboxDto<Form>
When I land on the membershipform.cshtml page, I get the following exception stating:
The model item passed into the dictionary is of type 'AdminSite.Models.MembershipFormDto', but this dictionary requires a model item of type 'AdminSite.Infrastructure.Models.InboxDto`1[BusinessLogic.Inbox.Form]'.
From everything I can tell, MembershipFormDto IS-A InboxDto of type MembershipForm, where MembershipForm IS-A Form. What gives?
This turned out to be an issue of covariance.
I added the following interface -
public interface IInboxDto<out T>
and modified the InboxDto class to implement that interface -
public abstract class InboxDto<T>: Dto<T>, IInboxDto<T> where T: Form { }
In short, covariance is going from a more defined type to a less defined type; specifically referencing a more defined object with a less defined reference. The reason the compiler complains is it's preventing a scenario like this:
List<String> instanciatedList = new List<String>;
List<Object> referenceList = instanciatedList;
referenceList.add(DateTime);
The final line makes sense, a DateTime IS-A Object. We've said referenceList is a List of Object. However it's instanciated as a List of String. A List of Object is more permissive than a List of String. Suddenly our guarantees from new List<String> are being ignored.
However the out and in keywords for Interface definitions tells the compiler to relax, we know what we're doing and understand what we're getting ourselves into.
More information.

Resources