Closed vtereshkov closed 2 years ago
Currently, not really, but this is definitely a feature that should exist.
This is a glaringly obvious gap in the language, so I'll put high priority on developing this feature so it will be in the next release
The current solutions to this kind of problem are not very great. The closest you can get to something like this is with explicit v-tables or enums.
import basics
import Vector2f
// ----------- ShapeVTable -----------
record ShapeVTable (f_defer, f_render ptr)
func makeShapeVTable(_ *$T) ShapeVTable {
return ShapeVTable(
func null &__defer__(*$T) as ptr,
func &render(*$T) as ptr
)
}
// ----------- Shape -----------
struct Shape (vtable ShapeVTable) {
func destroyAndFree {
if this.vtable.f_defer != null {
defer_function func(ptr) void = this.vtable.f_defer
defer_function(this)
}
delete this
}
func render {
render_function func(ptr) void = this.vtable.f_render
render_function(this)
}
}
// ----------- Rectangle -----------
struct Rectangle (struct Shape, size Vector2f) {
func render {
print("rectangle with size " + this.size.toString())
}
}
func Rectangle(w, h float) *Shape {
rect *Rectangle = new Rectangle
rect.vtable = makeShapeVTable(rect)
rect.size = vector2f(w, h)
return rect as *Shape
}
// ----------- Circle -----------
struct Circle (struct Shape, radius float) {
func render {
print("circle with radius " + this.radius)
}
}
func Circle(radius float) *Shape {
circle *Circle = new Circle
circle.vtable = makeShapeVTable(circle)
circle.radius = radius
return circle as *Shape
}
// ----------- main -----------
func main {
shapes <*Shape> List
defer {
each *Shape in shapes, it.destroyAndFree()
}
shapes.add(Rectangle(4.0, 5.0))
shapes.add(Circle(9.0))
each shape *Shape in shapes {
shape.render()
}
}
import basics
import Vector2f
enum ShapeKind (RECTANGLE, CIRCLE)
struct RectangleData (size Vector2f)
struct CircleData (radius float)
struct Shape (
kind ShapeKind,
union (
rectangle RectangleData,
circle CircleData
)
) {
func render {
exhaustive switch this.kind {
case ShapeKind::RECTANGLE
print("rectangle with size " + this.rectangle.size.toString())
case ShapeKind::CIRCLE
print("circle with radius " + this.circle.radius)
}
}
}
func Rectangle(w, h float) Shape {
shape POD Shape
shape.kind = ShapeKind::RECTANGLE
shape.rectangle.size = vector2f(w, h)
return shape
}
func Circle(radius float) Shape {
shape POD Shape
shape.kind = ShapeKind::CIRCLE
shape.circle.radius = radius
return shape
}
func main {
shapes <Shape> List
shapes.add(Rectangle(4.0, 5.0))
shapes.add(Circle(9.0))
each shape Shape in shapes {
shape.render()
}
}
Resolved!
Proper classes and virtual dispatch added in Adept 2.7
import basics
class Shape () {
constructor {}
virtual func draw {}
}
class Rectangle extends Shape (w, h float) {
constructor(w, h float) {
this.w = w
this.h = h
}
override func draw {
printf("Rectangle %f by %f\n", this.w, this.h)
}
}
class Circle extends Shape (radius float) {
constructor(radius float) {
this.radius = radius
}
override func draw {
printf("Circle with radius %f\n", this.radius)
}
}
func main {
shapes <*Shape> List
defer {
each *Shape in shapes, delete it
}
shapes.add(new Rectangle(4.0, 5.0) as *Shape)
shapes.add(new Circle(9.0) as *Shape)
each *Shape in shapes {
it.draw()
}
}
It looks like all polymorphic types in Adept are resolved at compile time. In other words, they are equivalent to C++ templates. Does Adept support virtual methods and run time polymorphism?
Consider a standard example: draw all the entities from a
List
ofShape
s, some of which areRectangle
s and others areCircle
s, according to the user's input. AnyShape
can bedraw()
n, but with different method implementations forRectangle
s andCircle
s. How to write this in Adept?