What can I do with virtual classes? - scala

I've seen (and heard) quite a bit of noise about adding virtual classes to Scala (it already has virtual types, according to Martin Odersky).
What is a layman's perspective (perhaps with an example) on what a virtual type is and what could be possible were Scala to have virtual classes?
([I have no experience with C or C++, so would prefer any answer not to refer to these languages].)

Virtual types are simple:
Classes and traits can have type members. E.g.
trait Foo {
type T
}
They can be refined (but not overridden once defined):
class Foo1 extends Foo {
type T <: AnyVal
}
class Foo2 extends Foo1 {
override type T = Boolean
}
class Foo3 extends Foo2 {
// override type T = Int // rejected by the compiler – would be unsound
}
Here is an example of virtual classes in a Java-descendent language (cclass is a virtual class):
Features of Virtual Classes
Let's look
to another example to study the
possibilities of virtual classes. We
will use virtual classes to extend a
collaboration with a totally new
funtionality. Let’s say we have a core
data model to represent expressions:
public cclass ExprModel {
abstract public cclass Expr {}
public cclass Constant extends Expr {
protected int _val;
public Constant(int val) {
_val = val;
}
}
abstract public cclass BinaryExpr {
protected Expr _left;
protected Expr _right;
public BinaryExpr(Expr left, Expr right) {
_left = left;
_right = right;
}
}
public cclass Add extends BinaryExpr {}
public cclass Mult extends BinaryExpr {}
}
The collaboration defines Expr as the
base class for all expressions,
concrete classes to represent
constants, addition and
multiplication. Class BinaryExpr
implements the common functionality of
all expressions with two operands.
Note that the current version of
Caesar does not support constructors
with parameters and abstract methods
in cclass. The code below demonstrates
how sample expressions can be built
using such collaboration:
public model.Expr buildSampleExpr(final ExprModel model) {
model.Expr const1 = model.new Constant(-3);
model.Expr const2 = model.new Constant(2);
model.Expr op1 = model.new Mult(const1, const2);
model.Expr const3 = model.new Constant(5);
model.Expr op2 = model.new Add(op1, const3);
return op2;
}
The collaboration defines Expr as the
base class for all expressions,
concrete classes to represent
constants, addition and
multiplication. Class BinaryExpr
implements the common functionality of
all expressions with two operands.
There are a lot of different
functionality related with
expressions: their evaluation,
formatting expressions to simple text
in infix or postfix order, various
consistency checks, lookups and
transformations. We want to keep all
this specific functionality separated
from each other and from the core data
model. This can be achieved with the
help of virtual classes. For example,
the collaboration below extends the
core model with simple expression
formatting functionality:
public cclass ExprFormat extends ExprModel {
abstract public cclass Expr {
abstract public void String format();
}
public cclass Constant {
public void String format() {
return _val < 0 ? “(“ + _val + “)” : “” + _val;
}
}
abstract public cclass BinaryExpr {
public void String format() {
return “(” + _left.format() + getOperSymbol()
+ _right.format() + “)”;
}
abstract public void String getOperSymbol();
}
public cclass Add {
public void String getOperSymbol() { return “+”; }
}
public cclass Mult {
public void String getOperSymbol() { return “*”; }
}
}
This short example demonstrates
various features of virtual classes:
There is no need to repeat inheritance relationships between
virtual classes if they are already
defined in the supercollaboration. For
example ExprModel defines Constant as
subclass of Expr. It means that
Constant is implicitly assumed as
subclass of Expr in ExprFormat as
well.
Virtual classes can use the fields and methods defined in their
older versions. For example
ExprFormat.BinaryExpr can use fields
_left and _right defined in ExprModel.BinaryExpr.
The functionality defined in the overridden virtual classes can be
accessed without type casts. For
example, fields _left and _right of
BinaryExpr were initially declared
with type Expr of ExprModel, which
does not have method format(), but in
the context of ExprFormat the new
version of Expr is assumed as the type
of _left and _right. So format() can
be called without any type casts.
The methods introduced in the overridden virtual classes can be
again overridden in the new versions
of subclasses. For example overridden
Expr introduces method format(), which
can be overridden in BinaryExpr. While
Add and Mult do not override this
method further, they inherit the
format() of BinaryExpr.
Besides the demonstrated properties,
the overridden virtual classes can
also
introduce new data fields,
implement new interfaces,
introduce new inheritance relationships.

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});
}

Call parent constructor with this as argument

I have a class that takes one of its subclasses as an argument. When constructing that subclass, I want to be able to use this as the value of that argument:
class A(val b: B)
class B extends A(this)
However, this fails to compile
this can be used only in a class, object, or template
[error] class B extends A(this)
[error] ^
Is there any way to get around this? I'm pretty sure that a pattern like this can be written in Java.
I'm not so sure about the last statement:
public class MyClass {
static class A {
A(B b) {
System.out.println(b.value);
}
}
static class B extends A {
String value;;
B() {
super(this);
value = "x";
}
}
public static void main(String args[]) {
new B();
}
}
gives the following error:
/MyClass.java:10: error: cannot reference this before supertype constructor has been called
super(this);
^
There is no good reason to attempt to let the this reference escape the scope of the constructor before the object itself has been constructed. Refactor it.

Relationship between a TypeScript class and an interface with the same name

I'm having a bit of trouble locating any clear documentation or explanation for the seemingly-special relationship between a TypeScript class and an interface with the same name.
What's the significance of an interface with the same name as a class?
Why does a class that shares its name with an interface implement that interface automatically?
Why does the compiler complain about my getter implementation of a readonly interface field when the class and interface have the same name, but accept the implementation if the names are different?
Is there any canonical documentation addressing these questions?
Code:
// Co-named interface and class doesn't like readonly property implementation:
interface Foo {
readonly x: number; // Error: Duplicate identifier 'x'
y: number;
}
class Foo {
get x(): number { // Error: Duplicate identifier 'x'
return 0;
}
y = 1;
}
// Same as above, but different class name + explicit `implements`
class Bar implements Foo {
get x(): number { // No error!
return 0;
}
y = 1;
}
// Duplicating the first example, but explicitly implementing the co-named interface:
interface Baz {
readonly x: number; // Error: Duplicate identifier 'x'
y: number;
}
class Baz implements Baz {
get x(): number { // Error: Duplicate identifier 'x'
return 0;
}
y = 1;
}
Interfaces of the same name within a module will be merged:
interface Foo {
x: number;
}
interface Foo {
y: string;
}
let g = {} as Foo;
g.x; // OK
g.y; // OK
A class declaration creates both a constructor function as well as type declaration, which essentially means that all classes can be used as interfaces.
class Bar {
y: number;
}
interface IBaz extends Bar { } // includes y: number
class CBaz implements Bar {
y: number = 5;
}
Therefore, having a class and an interface with the same name is equivalent to having two interfaces with the same name, and you will get merge conflicts if both instances of the interface re-declare the same members with different types.
Strangely enough, Typescript will allow for this:
export interface Foo {
readonly x: number;
}
export class Foo {
readonly x: number = 3;
}
but it won't allow get x() { return 3; } even though both of those generate as readonly x: number, so I can only imagine that the type checker considers them as different during merging even though they are semantically the same (this is why you can extend the interface and specify the readonly property as a getter function).
This is a limitation specific to accessors, and so far the Typescript team appears unwilling to comment on the issue.
class Foo {
readonly x: number = 0;
}
class Bar extends Foo {}
interface Bar {
readonly x: 2;
}
const bar = new Bar();
bar.x; // type is 2, no error
The team has commented that "[w]hether a property is implemented as a field or a getter/setter pair is an implementation detail, not part of the type," but this is clearly not the case as of Typescript 4.2:
class Baz extends Foo {
// error: "'x' is defined as a property in class 'Foo',
// but is overridden here in 'Baz' as an accessor."
get x() {
return 2;
}
}
I have no explanation for the team's responses. The comment that getters/setters are not part of the type system is from 2015 and may simply be outdated.

Haxe java.lang.Object Equivalent

Haxe allows class inheritance hierarchies
class Honda extends Car {
...
}
is there a common inheritance hierarchy root for all objects? I have a generic container class that could contain any object and I want to be able to declare
var _contents:Object; //Any class instance in _contents
How can I do this?
You can also use {} as a type, which will accept class instances as well as anonymous objects :
var _contents:{};
We also have Dynamic, which basically means "anything" (not only objects, but also primitives like Bool, Int, etc).
If your class is a generic container, you may want to type its content, though, using type parameters:
class Container<T> {
var _contents:T;
public function new(contents:T):Void {
_contents = contents;
}
}
And then:
var arrayContainer = new Container([]);
var stuffContainer = new Container({foo:"bar"});
var classContainer = new Container( new Stuff() );
The inheritance root for classes is Class<T> so the following should work:
var _contents:Class<T>;
However, to store an Enum, you would have to use Enum<T> instead.
From the manual:
There is a special type in Haxe which is compatible with all classes:
Define: Class<T>
This type is compatible with all class types which means that all classes (not their instances) can be assigned to it. At compile-time, Class<T> is the common base type of all class types. However, this relation is not reflected in generated code.
This type is useful when an API requires a value to be a class, but not a specific one. This applies to several methods of the Haxe reflection API.

Pointer to a derived class C++

I'm having some trouble with deriving a pointer to a derived class. I think it has something to do with a constructor. Do I have to create a new constructor in my derived class? How to I create a pointer from a derived class? Thanks
Class Base
{
public:
int myfunction(int a,int b,int c)
{
return a+b+c;
}
};
Class Derived: public Base
{
int newfunction(int a, int b, int c)
{
return a*b*c;
};
};
int main()
{
// this doesn't work at all.. I get all errors every time I try to refer to the object
//instantiated from my derived class.
//I know it's my lack of understanding.
Derived *NewObject = new Derived;
//Why wont this work?
}
C++ is case sensitive, and the keyword class is lowercase. You wrote Class for both classes, and it looks like it's the only issue with your code.