inheritance and polymorphism together in golang, are possible? - go

This question comes form the porting I have to do from a working logic of C++ program, to a golang context.
This is just an example, and i see how wierd it can be, but think about the logic behind it.
If the explanation bores you, go to the code, it is pretty self explanatory.. otherwise I try to explain.
The concept is that I have a base class that contains a method with common logic, but that methot use virtual function that each descendant need to implement.
In go, I easly achieve inheritance of the base method, but the polimorphic adaptation to the descendant it's complicate (for me): I can't figure out how replicate this mechanism..
class TPolygon{
private:
int nside;
public:
TPolygon(int n){ nside=n; }
virtual float Area()=0;
float MeanArea(){ return Area()/nside; }
};
class TSquare: public TPolygon{
private:
float side;
public:
TSquare(float sidelen):TPolygon(4){ side=sidelen; }
float Area(){ return side*side; }
};
class TTriangle: public TPolygon{
private:
float base, height;
public:
TTriangle(float b, float h):TPolygon(3){ base=b; height=h; }
float Area(){ return base*height/2; }
};
TSquare *square=new TSquare(2.0);
square->MeanArea(); // -> 2*2 / 4 correct
TTriangle *triangle=new TTriangle(5.0, 6.0);
triangle->MeanArea(); // -> 5*6/2 / 3 correct
in go i tried:
type TPolygon struct {
nside int
}
func (p *TPolygon) Area() float64 {
return 0
}
func (p *TPolygon) MeanArea() float64 {
return p.Area() / float64(p.nside)
}
type TSquare struct {
TPolygon
side float64
}
func NewSquare(sidelength float64) *TSquare {
return &TSquare{
TPolygon: TPolygon{nside: 4},
side: sidelength,
}
}
func (s *TSquare) Area() float64 {
return s.side * s.side
}
type TTriangle struct {
TPolygon
base, height float64
}
func NewTriangle(b, h float64) *TTriangle {
return &TTriangle{
TPolygon: TPolygon{nside: 3},
base: b,
height: h,
}
}
func (t *TTriangle) Area() float64 {
return t.base * t.height / 2
}
square := NewSquare(2.0)
square.MeanArea() // -> 0 from TPolygon.Area()
The only way I found to achieve this, is a workaround that break the DRY principle because need to repeat the same method in each descendant
func (p *TPolygon) meanArea2(a float64) float64 {
return a / float64(p.nside)
}
func (s *TSquare) MeanArea2() float64 {
return s.meanArea2(s.Area())
}
func (t *TTriangle) MeanArea2() float64 {
return t.meanArea2(t.Area())
}
square.MeanArea2() // -> 1 as expected
and moreover, isn't always easy and possible to refactor this way, if the logic get more complicate..
Does anybody knows if this architecture is possible in golang, and how?
Or if there is other workaround that get close?

There are ways to emulate inheritance, but the following is much cleaner. It allows calculating the area/nsides value for any type that implements the two methods:
type MeanAreaSupport interface {
NSides() int
Area() float64
}
func MeanArea(shape MeanAreaSupport) float64 {
return shape.Area()/shape.NSides()
}

Related

What's the idiomatic replacement for glsl output parameters in wgsl?

In glsl and hlsl, I can define a function like this:
float voronoi(vec2 x, out int2 cell) {
cell = ...
return ...
}
However, it doesn't seem like this is possible in wgsl.
What's the intended replacement for this? I guess I could define a VoronoiResult struct, but it seems overly boilerplate heavy:
struct VoronoiResult {
cell: vec2<i32>;
distance: f32;
};
fn voronoi(x: vec2<f32>) -> VoronoiResult {
// ...
var ret: VoronoiResult;
ret.distance = distance;
ret.cell = cell;
return ret;
}
The equivalent would be to use a pointer argument:
fn voronoi(x: vec2<f32>, cell: ptr<function, vec2<i32>>) -> f32 {
*cell = vec2(1, 2);
return 1.f;
}
#compute #workgroup_size(1)
fn main() {
var a: vec2<i32>;
var f = voronoi(vec2(1.f, 1.f), &a);
}
This produces the HLSL:
float voronoi(float2 x, inout int2 cell) {
cell = int2(1, 2);
return 1.0f;
}
[numthreads(1, 1, 1)]
void main() {
int2 a = int2(0, 0);
float f = voronoi((1.0f).xx, a);
return;
}
You can also make the struct version shorter by using the struct initializer:
struct Out {
cell: vec2<i32>,
val: f32,
}
fn voronoi(x: vec2<f32>) -> Out {
return Out(vec2(1, 2), 1.f);
}
#compute #workgroup_size(1)
fn main() {
var f = voronoi(vec2(1.f, 1.f));
}

Could a method return a pointer with return type of this method is value

I saw a piece of code as below:
Just wondering as the value method of draw() have been implemented, why could it return the pointer of the struct in fact.
type Shape interface {
draw()
}
type Rectangle struct {
}
func (Rectangle) draw() {
fmt.Println("Draw Rectangle")
}
type Square struct {
}
func (Squre) draw() {
fmt.Println("Draw Square")
}
type Circle struct {
}
func (Circle) draw() {
fmt.Println("Draw Circle")
}
type ShapeFactory struct {
}
func (*ShapeFactory) CreateShape(shape string) Shape {
if shape == "Rectangle" {
return &Rectangle{}
} else if shape == "Square" {
return &Square{}
} else if shape == "Circle" {
return &Circle{}
}
return nil
}
I think should it be like below to implement a pointer method so that the method CreateShape could return the pointer of struct?
type Rectangle struct {
}
func (*Rectangle) draw() {
fmt.Println("Draw Rectangle")
}
The return type defined on the CreateShape method is not a struct but an interface. Therefore CreateShape can return any type as long as it implements the Shape interface.

Idiomatic way to create static iterable collection of named structs?

What is the idiomatic way to create static iterable collection of named structs? I have n instances of a struct, where n is known at compile time and is less than 20. I would like to be able to iterate over all the entries and also be able to refer to each entry by a name instead of an index. All the data is known at compile time.
I could use an array or enum, along with hand written constants which map the labels to indexes; but this seems finicky.
fn common_behaviour(x: f64) {
print!("{}", x);
}
const ADD: usize = 0;
const SUBTRACT: usize = 1;
fn main () {
let mut foos: [f64; 2] = [0.0; 2];
foos[ADD] = 4.0;
foos[SUBTRACT] = 2.0;
for foo in &foos {
common_behaviour(*foo);
}
foos[ADD] += 1.0;
foos[SUBTRACT] -= 1.0;
}
Alternatively, I could just pay the performance cost and use a HashMap as the hashing overhead might not actually matter that much, but this seems suboptimal as well.
Perhaps, I could refactor my code to use function pointers instead special casing the different special cases.
fn common_behaviour(x: f64) {
print!("{}", x);
}
fn add(x: f64) -> f64 {
x + 1.0
}
fn subtract(x: f64) -> f64 {
x - 1.0
}
struct Foo {
data: f64,
special: fn(f64) -> f64
}
impl Foo {
fn new(data: f64, special: fn(f64) -> f64) -> Foo {
Foo { data, special }
}
}
fn main() {
let mut foos = [Foo::new(4.0, add), Foo::new(2.0, subtract)];
for foo in &mut foos {
common_behaviour(foo.data);
foo.data = (foo.special)(foo.data);
}
}
What is most idiomatic way to handle this situation?
Looking at:
fn main() {
let mut foos = [Foo::new(4.0, add), Foo::new(2.0, subtract)];
for foo in &mut foos {
common_behaviour(foo.data);
foo.data = (foo.special)(foo.data);
}
}
I see a Command Pattern struggling to emerge, and Rust is great at expressing this pattern, thanks to enum:
enum Foo {
Add(f64),
Sub(f64),
}
impl Foo {
fn apply(&mut self) {
match self {
Foo::Add(x) => {
Self::common(*x);
*x += 1.0;
},
Foo::Sub(x) => {
Self::common(*x);
*x -= 1.0;
},
}
}
fn common(x: f64) {
print!("{}", x);
}
}
And your example becomes:
fn main() {
let mut foos = [Foo::Add(4.0), Foo::Sub(2.0)];
for foo in &mut foos {
foo.apply();
}
}

Is it possible to calculate the return type of a Rust function or trait method based on its arguments?

Can I achieve something similar to boost::math::tools::promote_args in Rust? See also Idiomatic C++11 type promotion
To be more specific: is it possible to calculate the return type of a function or trait method based on its arguments and ensure, that the return type has the same type as one of the arguments?
Consider the following case. I have two structs:
#[derive(Debug, Clone, Copy)]
struct MySimpleType(f64);
#[derive(Debug, Clone, Copy)]
struct MyComplexType(f64, f64);
where MySimpleType can be promoted to MyComplexType via the From trait.
impl From<MySimpleType> for MyComplexType {
fn from(src: MySimpleType) -> MyComplexType {
let MySimpleType(x1) = src;
MyComplexType(x1, 0.0)
}
}
I want to write a function that takes two arguments of types MySimpleType or MyComplexType and return a value of type MySimpleType if all arguments are typed as MySimpleType, otherwise the function should return a value of type MyComplexType. Assuming I have implemented Add<Output=Self> for both types I could do something like this:
trait Foo<S, T> {
fn foo(s: S, t: T) -> Self;
}
impl<S, T, O> Foo<S, T> for O
where O: From<S> + From<T> + Add<Output = Self>
{
fn foo(s: S, t: T) -> Self {
let s: O = From::from(s);
let t: O = From::from(t);
s + t
}
}
but then the compiler doesn't know that O should be either S or T and I have to annotate most method calls.
My second attempt is to use a slightly different trait and write two implementations:
trait Foo<S, T> {
fn foo(s: S, t: T) -> Self;
}
impl Foo<MySimpleType, MySimpleType> for MySimpleType {
fn foo(s: MySimpleType, t: MySimpleType) -> Self {
s + t
}
}
impl<S, T> Foo<S, T> for MyComplexType
where MyComplexType: From<S> + From<T>
{
fn foo(s: S, t: T) -> Self {
let s: MyComplexType = From::from(s);
let t: MyComplexType = From::from(t);
s + t
}
}
but again, the compiler isn't able to figure the return type of
Foo::foo(MySimpleType(1.0), MySimpleType(1.0))
The third attempt is something similar to the std::ops::{Add, Mul, ...}. Use an associated type and write a specific implementation for each possible combination of argument types
trait Foo<T> {
type Output;
fn foo(self, t: T) -> Self::Output;
}
impl<T: Add<Output=T>> Foo<T> for T {
type Output = Self;
fn foo(self, t: T) -> Self::Output {
self + t
}
}
impl Foo<MySimpleType> for MyComplexType {
type Output = Self;
fn foo(self, t: MySimpleType) -> Self::Output {
let t: Self = From::from(t);
self + t
}
}
impl Foo<MyComplexType> for MySimpleType {
type Output = MyComplexType;
fn foo(self, t: MyComplexType) -> Self::Output {
let s: MyComplexType = From::from(self);
s + t
}
}
This seems to be the best solution until one needs a function with n arguments. Because then one has to write 2^n - n + 1 impl statements. Of course, this gets even worse if more then two types being considered.
===
Edit:
In my code I've multiple nested function calls and I want to avoid non necessary type promotion, since the evaluation of the functions for the simple type is cheap and expensive for the complex type. By using #MatthieuM. 's proposed solution, this is not achieved. Please consider the following example
#![feature(core_intrinsics)]
use std::ops::Add;
trait Promote<Target> {
fn promote(self) -> Target;
}
impl<T> Promote<T> for T {
fn promote(self) -> T {
self
}
}
impl Promote<u64> for u32 {
fn promote(self) -> u64 {
self as u64
}
}
fn foo<Result, Left, Right>(left: Left, right: Right) -> Result
where Left: Promote<Result>,
Right: Promote<Result>,
Result: Add<Output = Result>
{
println!("============\nFoo called");
println!("Left: {}", unsafe { std::intrinsics::type_name::<Left>() });
println!("Right: {}",
unsafe { std::intrinsics::type_name::<Right>() });
println!("Result: {}",
unsafe { std::intrinsics::type_name::<Result>() });
left.promote() + right.promote()
}
fn bar<Result, Left, Right>(left: Left, right: Right) -> Result
where Left: Promote<Result>,
Right: Promote<Result>,
Result: Add<Output = Result>
{
left.promote() + right.promote()
}
fn baz<Result, A, B, C, D>(a: A, b: B, c: C, d: D) -> Result
where A: Promote<Result>,
B: Promote<Result>,
C: Promote<Result>,
D: Promote<Result>,
Result: Add<Output = Result>
{
let lhs = foo(a, b).promote();
let rhs = bar(c, d).promote();
lhs + rhs
}
fn main() {
let one = baz(1u32, 1u32, 1u64, 1u32);
println!("{}", one);
}
I would expect the simplest way to implement promotion is to create a Promote trait:
trait Promote<Target> {
fn promote(self) -> Target;
}
impl<T> Promote<T> for T {
fn promote(self) -> T { self }
}
Note: I provide a blanket implementation as all types can be promoted to themselves.
Using associated types is NOT an option here, because a single type can be promoted to multiple types; thus we just use a regular type parameter.
Using this, a simple example is:
impl Promote<u64> for u32 {
fn promote(self) -> u64 { self as u64 }
}
fn add<Result, Left, Right>(left: Left, right: Right) -> Result
where
Left: Promote<Result>,
Right: Promote<Result>,
Result: Add<Output = Result>
{
left.promote() + right.promote()
}
fn main() {
let one: u32 = add(1u32, 1u32);
let two: u64 = add(1u32, 2u64);
let three: u64 = add(2u64, 1u32);
let four: u64 = add(2u64, 2u64);
println!("{} {} {} {}", one, two, three, four);
}
The only issue is that in the case of two u32 arguments, the result type must be specified otherwise the compiler cannot choose between which possible Promote implementation to use: Promote<u32> or Promote<u64>.
I am not sure if this is an issue in practice, however, since at some point you should have a concrete type to anchor type inference. For example:
fn main() {
let v = vec![add(1u32, 1u32), add(1u32, 2u64)];
println!("{:?}", v);
}
compiles without type hint, because add(1u32, 2u64) can only be u64, and therefore since a Vec is a homogeneous collection, add(1u32, 1u32) has to return a u64 here.
As you experienced, though, sometimes you need the ability to direct the result beyond what type inference can handle. It's fine, you just need another trait for it:
trait PromoteTarget {
type Output;
}
impl<T> PromoteTarget for (T, T) {
type Output = T;
}
And then a little implementation:
impl PromoteTarget for (u32, u64) {
type Output = u64;
}
impl PromoteTarget for (u64, u32) {
type Output = u64;
}
With that out of the way, we can rewrite baz signature to correctly account for all intermediate types. Unfortunately I don't know any way to introduce aliases in a where clause, so brace yourself:
fn baz<Result, A, B, C, D>(a: A, b: B, c: C, d: D) -> Result
where
A: Promote<<(A, B) as PromoteTarget>::Output>,
B: Promote<<(A, B) as PromoteTarget>::Output>,
C: Promote<<(C, D) as PromoteTarget>::Output>,
D: Promote<<(C, D) as PromoteTarget>::Output>,
(A, B): PromoteTarget,
(C, D): PromoteTarget,
<(A, B) as PromoteTarget>::Output: Promote<Result> + Add<Output = <(A, B) as PromoteTarget>::Output>,
<(C, D) as PromoteTarget>::Output: Promote<Result> + Add<Output = <(C, D) as PromoteTarget>::Output>,
Result: Add<Output = Result>
{
let lhs = foo(a, b).promote();
let rhs = bar(c, d).promote();
lhs + rhs
}
Link to the playground here, so you can check the result:
============
Foo called
Left: u32
Right: u32
Result: u32
4

Eliminating the duplication of methods

Is it possible to refactor the following code to eliminate the duplication?
I want my GameObject implement the logic for "update" task invoking different update handlers (like my "AfterUpdate"). The current version works, but there are two implementations of "Update" and they are equal.
AfterUpdate invoked on GameObject should operate on its properties, AfterUpdate invoked on HeroGameObject should have access to HeroGameObject's properties (like "health" for example).
What can I do better? Thank you.
package main
import "fmt"
type Point struct {
x, y int
}
///////////////////////
type GameObject struct {
Point
title string
status int
ticks float32
spriteIndex int
}
func (g *GameObject) Update() {
if g.ticks == 0 {
g.spriteIndex++
g.AfterUpdate()
}
}
func (g *GameObject) AfterUpdate() {
g.status = 0 //suppose it does something meaningful
fmt.Println("GameObject afterUpdate handler invoked")
}
///////////////////////
type HeroGameObject struct {
GameObject
health float32
}
func (h *HeroGameObject) Update() {
if h.ticks == 0 {
h.spriteIndex++
h.AfterUpdate()
}
}
func (h *HeroGameObject) AfterUpdate() {
h.health-- //suppose it does something meaningful but *different*, using its own properties, for example "health"
fmt.Println("HeroGameObject afterUpdate handler invoked")
}
///////////////////////
func main() {
gameObject := &GameObject{
Point: Point{
x: 0,
y: 0,
},
title: "dummy object",
status: 0,
ticks: 0,
spriteIndex: 0,
}
heroObject := &HeroGameObject{
GameObject: GameObject{
Point: Point{
x: 0,
y: 0,
},
title: "hero object",
status: 0,
ticks: 0,
spriteIndex: 0,
},
health: 0,
}
gameObject.Update()
heroObject.Update()
}
The output:
GameObject afterUpdate handler invoked
HeroGameObject afterUpdate handler invoked
UPDATED
I've come up with the following solution and I wonder what do you think:
package main
import "fmt"
type Point struct {
x, y int
}
///////////////////////
type IHandler interface {
afterUpdate()
}
type GameObject struct {
Point
title string
status int
ticks float32
spriteIndex int
handler IHandler
}
func (g *GameObject) SetHandler(h IHandler) {
g.handler = h
}
func (g *GameObject) Update() {
if g.ticks == 0 {
g.spriteIndex++
if g.handler != nil {
g.handler.afterUpdate()
}
}
}
//actually it is IHandler specific implementation number one
func (g *GameObject) afterUpdate() {
g.status = 0 //suppose it does something meaningful
fmt.Println("GameObject afterUpdate handler invoked")
}
///////////////////////
type HeroGameObject struct {
GameObject
health float32
}
// note, this method is commented out
/*
func (h *HeroGameObject) Update() {
if h.ticks == 0 {
h.spriteIndex++
h.AfterUpdate()
}
}*/
//actually it is IHandler specific implementation number two
func (h *HeroGameObject) afterUpdate() {
h.health-- //suppose it does something meaningful but *different*, using its own properties, for example "health"
fmt.Println("HeroGameObject afterUpdate handler invoked")
}
///////////////////////
func main() {
gameObject := &GameObject{
Point: Point{
x: 0,
y: 0,
},
title: "dummy object",
status: 0,
ticks: 0,
spriteIndex: 0,
}
gameObject.SetHandler(gameObject) //!
heroObject := &HeroGameObject{
GameObject: GameObject{
Point: Point{
x: 0,
y: 0,
},
title: "hero object",
status: 0,
ticks: 0,
spriteIndex: 0,
},
health: 0,
}
heroObject.SetHandler(heroObject) //!
gameObject.Update()
heroObject.Update()
}
http://play.golang.org/p/GIwOknSSzx
Is it okay to have "gameObject.SetHandler(gameObject)"?
How about using flag function and base interface, like this?
type BaseGameObject interface {
Ticks() int
IncSpriteIndex()
AfterUpdate()
}
func UpdateGameObject(o BaseGameObject) {
if o.Ticks() == 0 {
o.IncSpriteIndex()
o.AfterUpdate()
}
}
func (o *GameObject) Ticks() int {
return o.ticks
}
func (o *GameObject) IncSpriteIndex() {
o.spriteIndex++
}

Resources