Listen changes on abstract variable - class

So I have this abstract class:
export abstract class Foo {
// Can't do this, but I want to make sure the implementation sets "name"
//abstract name: string;
set name(value: string) {
// Do things
}
}
As I state in the code, I want to listen to the changes made to the attribute name inside Foo class, but keeping it abstract to make sure the programmer sets/implements the attribute somewhere.
Is there a way to make sure the programmer sets that variable or, at least, requires him to declare it.
Not sure if this is possible.

You can have a protected constructor which receives the name:
abstract class Foo {
protected constructor(public name: string) {}
}
Or you can declare an abstract method which returns it:
abstract class Foo {
public name: string;
protected constructor() {
this.name = this.getName();
}
protected abstract getName(): string;
}
You can call getName in a different place/time instead of in the constructor.

Related

"'Class.field=' isn't a valid override" when overriding a field with a more specific type

abstract class Ainterface {
String? name;
List<Binterface?>? list;
}
abstract class Binterface {
String? age;
int? len;
}
class ObjA extends Ainterface {
String? name;
List<ObjB?>? list;
ObjA({this.name, this.list});
}
class ObjB extends Binterface {
String? age;
int? len;
ObjB({this.age, this.len});
}
I used objb as the type of each item in the list, but the editor gave an error 'obja. List =' ('void function (list < objb? >?)) isn't a valid override of 'Ainterface.list=' ('void Function(List<Binterface?>?)').
How I can solve this problem?
Fields (data members) in Dart implicitly provide getters and setters as part of the interface. Therefore when you write:
abstract class Ainterface {
List<Binterface?>? list;
}
The interface is implicitly:
abstract class Ainterface {
List<Binterface?>? get list;
set list(List<Binterface?>? value);
}
The problem is that your derived class wants to provide an interface:
class ObjA extends Ainterface {
List<ObjB?>? get list;
set list(List<ObjB?>? value);
}
Even though List<ObjB?>? is substitutable for List<Binterface?>?, the reverse is not true: List<Binterface?>? is not substitutable for List<ObjB?>?, and that's the direction that matters for the setter.
The list setter in ObjA is not a safe override of the corresponding setter from Ainterface because it would allow callers to violate its contract. Ainterface.list advertises that it allows being set to any instance of a Binterface, but ObjA.list expects only an instance of ObjB. As a concrete example, if the override were allowed, then the following code would compile without error:
class AnotherB extends Binterface {}
void main() {
Ainterface a = ObjA();
a.list = [AnotherB()]; // This error would not be caught at compile-time.
}
And now a.list contains a List<AnotherB> even though ObjA.list expects List<ObjB>, and you'd eventually get an error at runtime if you try to use a.list as a List<ObjB>.
If you can logically guarantee that the above scenario will never happen, then you can use the covariant keyword to relax static type-checking and allow the override:
abstract class Ainterface {
covariant List<Binterface?>? list;
}
but I re-emphasize that the above code removes some type-safety. By using the covariant keyword, you take responsibility for ensuring that you do not violate the contract in practice.
Alternatively:
Reconsider if your abstract base class needs to expose setters as part of its interface, and expose only getters if possible.
Make Ainterface a generic class parameterized on the concrete type of Binterface:
abstract class Ainterface<DerivedB extends Binterface> {
List<DerivedB?>? list;
}
class ObjA extends Ainterface<ObjB> {
List<ObjB?>? list;
}
I'll also point out that overriding fields is usually a bad idea, and you usually should be explicitly overriding getters and setters anyway.
In the Ainterface abstract class you declared that a list should be declared of type Binterface so any class extending that class should do that. so when you want to declare a class extending this class you should consider that. if you want to also declare a list from type ObjB you can do it after that. it will be like this:
class ObjA extends Ainterface {
String? name;
List<Binterface?>? list;
List<ObjB ?>? list2;
ObjA({this.name, this.list, this.list2});
}

Get type of an object in a Haxe macro

I would like to get the class of an object in a macro so that I can access its static variables:
// autoBuild macro adds static field "id_ : Int" to all subclasses
class Base {
}
class Child1 extends Base {
public function new() {}
}
class Child2 extends Base {
public function new() {}
}
class Container {
public function addChild(index: Int, object: Base) {}
macro function add(object: ???) {
// find out class of on object
// ???
// var id = class.id_;
this.addChild(id, object);
}
}
Desired usage:
var c = new Container();
c.add(new Child1());
c.add(new Child2());
You can use Context.typeof() to get the expression's type - then you need to do a bit of pattern matching to find out the type's name. The following only works with classes because it only matches TInst, but could be extended:
import haxe.macro.Context;
import haxe.macro.Expr;
class Container {
// [...]
public macro function add(self:Expr, object:Expr):Expr {
var name = switch (Context.typeof(object)) {
case TInst(_.get() => t, _): t.name;
case _: throw "object type not found";
}
return macro $self.addChild($i{name}.id_, $object);
}
}
This will generate the following code:
var c = new Container();
c.addChild(Child1.id_, new Child1());
c.addChild(Child2.id_, new Child2());
Note that accessing _id via it's unqualified name is only safe if it's actually imported (or toplevel) - in practice you'd want to use t.pack in combination with $p{} to generate the fully qualified path.

Why can't I "implements" an all-optional interface in TypeScript 2.4+?

I wrote some code:
interface IEventListener {
onBefore?(name: string): void;
onAfter?(name: string): void;
}
class BaseListener implements IEventListener {
stuff() {
}
}
The intent here is that someone can derive from BaseListener and get correct typechecking on their onBefore / onAfter methods:
class DerivedListener extends BaseListener {
// Should be an error (name is string, not number)
onBefore(name: number) {
}
}
However, I don't get an error in DerivedListener. Instead I got an error in BaseListener:
Type "BaseListener" has no properties in common with type "IEventListener"
What's going on?
The implements clause in TypeScript does exactly one thing: It ensures that the declaring class is assignable to the implemented interface. In other words, when you write class BaseListener implements IEventListener, TypeScript checks that this code would be legal:
var x: BaseListener = ...;
var y: IEventListener = x; // OK?
So when you wrote class BaseListener implements IEventListener, what you probably intended to do was "copy down" the optional properties of IEventListener into your class declaration.
Instead, nothing happened.
TypeScript 2.4 changed how all-optional types work. Previously, any type which didn't have properties of a conflicting type would be assignable to an all-optional type. This leads to all sorts of shenanigans being allowed:
interface HttpOptions {
method?: string;
url?: string;
host?: string;
port?: number;
}
interface Point {
x: number;
y: number;
}
const pt: Point = { x: 2, y: 4 };
const opts: HttpOptions = pt; // No error, wat?
The new behavior as of 2.4 is that an all-optional type requires at least one matching property from the source type for the type to be considered compatible. This catches the above error and also correctly figures out that you tried to implements an interface without actually doing anything.
Instead what you should do is use declaration merging to "copy down" the interface members into your class. This is as simple as writing an interface declaration with the same name (and same type parameters, if any) as the class:
interface IEventListener {
onBefore?(name: string): void;
onAfter?(name: string): void;
}
class BaseListener {
stuff() {
}
}
interface BaseListener extends IEventListener { }
This will cause the properties of IEventListener to also be in BaseListener, and correctly flag the error in DerivedListener in the original post.

How to define func to a specific case of Enum in Swift?

enum Type {
case A
case B
func do() {
}
}
I would like do for available for case A
I don't think what you want is possible with enums.
However, it can be done with tricks.
First, create a class called Type:
class Type { private init() {} }
And create two classes, AType and BType to inherit Type:
// Put this in the same file as Type
class AType: Type { private init() {} }
class BType: Type { private init() {} }
The private initializer is to prevent external code to create AType and BType objects.
In Type, add these static properties:
static let A = AType()
static let B = BType()
Then you're basically done!
To add a method that only Type.A is accessible, just add it in the AType class!
This way, just like an enum, Type.A and Type.B can still be assigned to a Type object!

Getting an argument from a private constructor

I want to get access to an argument in a private constructor without using mutable variables:
class Class1 {
val strArgPublic = // get strArg argument from the private constructor. How?
private def this(strArg: String) = {
//.....
}
}
I want not only get strArg and return it, but change it a little bit and return a new modified copy of it.
How can I do this?
There is not only private constructor in your class. There is also a public constructor. You should decide what will be a value of strArgPublic after public constructor. If there is should be no public constructor you should define your class like this:
class Class1 private(strArg: String) {
val strArgPublic = transform(strArg)
}
If there should be a parameterless public constructor you could define one as auxiliary constructor:
class Class1 private(strArg: String) {
val strArgPublic = transform(strArg)
def this() = this("default")
}