Given this scenario:
import physics as p
import vector as v
...
point := p.new_point(1,3) // <- struct Point { x, y }
vector := v.new_vector2D(4,5) // <- struct Vector2D { x, y }
Now we want to be able to pass these identical structs around between modules, while avoiding having to use custom converting functions every time. Which can be confusing or even lead to having whole modules for converting between types.
The idea here is that they're basically the same type of struct so explicitly converting them would be nice:
rotated_vector := v.rotate(Vector2D(point))
Maybe even allow magic like:
rotated_vector := v.rotate(point) :scream:
what about simple cast ?
struct Vector{
x int
y int
}
struct Point{
x int
y int
}
fn main() {
vector := Vector{1,2}
point := Point(v)
}
no functions, no union, no typedef
currently, this "simple cast" only works with a union, eg:
struct Vector{
x int
y int
}
struct Point{
x int
y int
}
union Mix {
v Vector
p Point
}
fn main() {
v := Vector{1, 2}
p := Mix(v).p
println('p=$p')
}
Shouldn't we do with an interface rather than cast?
interface I2D {
x int
y int
}
fn rotate(td I2D)
{
...
}
rotated_vector := rotate(point)
Reason: What if we want to extend Point with color
struct Point{
x int
y int
color string
}
If already existing code depends on the identical structs conversion, we cannot extend easily
rotated_vector := rotate(point)
never mind the above comment. You want vector as the returned type rather than point, while you're passing point.
IMHO: I like explicit conversion to avoid the risk of unexpected limitations of future extension than implicit conversion
On the second thought, for
You want vector as the returned type rather than point, while you're passing point.
part, IMHO, what we should code is actually below to keep future possible Point extendability.
interface I2D {
x int
y int
}
fn rotate(td I2D) Vector
{
v := Vector{td.X, td.Y}
// remaining operation
return v
}
I guess the purpose of that issue is focused on "identical" structs, hence its title
if that is true, I guess that it is not expected that one of the two "identical" structs might "evolve",
else they would not be identical anymore
correct me if I'm wrong, @Larpon ; because if I am, then we're talking about a different sort of "automagic" implementation :-)
I am talking about identical structs with identical field names in identical order. @takkyuuplayer you'll have the same problem when an interface change I believe, you still need to edit your code?
Code need to be adapted/changed no matter what when some relation changes. Interfaces also force a stronger bond between modules. I'm trying to avoid modules have to know anything about each other. So Point from module x can be used in module y and vice versa.
@elimisteve helped clarify that the exact same thing I think of is possible in Go. I don't think we'd need more complexity.
Keep it simple and explicit:
// In module "vector"
struct Vector{
x int
y int
}
// In module "point"
struct Point{
x int
y int
}
pub fn (p mut Point) add(by Point) {
p.x += by.x
p.y += by.y
}
// In main.v
import { vector, point, convert }
fn main() {
v := vector.Vector{1, 1}
mut p := point.Point{2, 2}
// p.add(v) // <- I agree this could lead to confusion
p.add(point.Point(v)) // <- ... so this is more explicit
// p.add(convert.vector_to_point(v)) // <- ... avoiding this
}
p.add(point.Point(v)) // <- ... so this is more explicit
This one looks good!