#Simulate Implicit Conversion

1 messages · Page 1 of 1 (latest)

slate canopy
#

In C++, each type has an operator that converts it to another type. If this operator is not declared explicit, the conversion will be implicit, so if the compiler sees that converting one type to another is possible, it will do that without the user telling it to.

How do you achieve this behavior in Julia?

struct Vector2f
  x::Number
  y::Number
end

foo(vec::Vector2f) = # ...

I want to be able to call foo with a tuple of numbers, e.g. foo((1, 2)) should be the same as foo(Vector2f(1, 2)).

In C++, for this to be possible you would add a conversion operator which in Julia would be

julia> Vector2f(x::Tuple) = return Vector2f(x[1], x[2])
julia> convert(::Type{Vector2f}, x::Tuple) = return Vector2f(x)

But

julia> foo((1, 2))
ERROR: MethodError: no method matching foo(::Tuple{Int64, Int64})

Closest candidates are:
  foo(::Vector2f)
   @ Main REPL[2]:1

To be clear, I want any function taking a Vector2f to also be able to take a Tuple, without adding a method to the function, foo in this case.

Is there a way for this to be doable?

worn elk
#
foo(x) = foo(convert(Vector2f,x))
#

Wait... you don't want to add a method to a function?

#

Oh, then you're screwed.

slate canopy
#

I feel like you can hack this by associating Vector2f and Tuple on the type tree

#

since promotion does work for subtypes

#

but idk how

#

maybe it's just not possible and I need to write a macro that defines the methods for the like 400 functions I need this for

worn elk
#

for i in ...
eval(:(...))

#

The conversion code can be eval-ed.

#

Julia uses multiple dispatch conversion as a paradigm.

#

Better not go against it.

slate canopy
#

In C++ you can call the following function:

void foo(Vector2f vecs...) { // ...

// can be called as
foo({1, 2}, {3, 4}, {5, 6})

But in Julia

foo(vecs::Vector2f...) = # ...

# needs to be called as
foo(Vector2f(1, 2), Vector2f(3, 4), Vector2f(5, 6))

which is like 10 times the number of characters

#

it seems small but it makes things that are a one-liner in C++ be like 4 lines in Julia

worn elk
slate canopy
#

I know I can do a new method but I need to write that for like 60 functions and then test all of those too qq

#

but maybe that is the only way

#

also I was hoping someone could teach me a new technique that I was too dumb to come up with but maybe there just isn't any technique for this in Julia

worn elk
#

Well, if only the function names change, you can do the eval trick.

#

Julia is a no-implicit-conversion language. Implicit conversion complicates the deal.

#

With implicit conversion, well, it's an implicit function call that the function can suddenly support something.

worn elk
#

Then you can use this pattern.

#

Well, if you think this is bad... check out my cursed trait system library.

lapis prairie
#

you could make v2f(x,y) = Vector2f(x,y)

#

just shortening the constructor's name

jagged trail
#

I'll ask you a question from another angle: why do you work with tuples of numbers so often in your vector math that you need a convenient converter for them? If you have vector types, why not do all your math with vector types and forget about tuples?

slate canopy
#

that's what I'm doing right now

#

it's just really annoying to write I don't like the syntax

#

my vector type is custom and I defined all the operators for it

#

this is basically just a question of whether i can make it have prettier syntax without having to add a million methods but apparently no, I need to add a million mehtods

#

one example of this is:

foo(x::Cfloat) = #...
foo(x::Number) = foo(convert(Cfloat, x))
#

With just the first method users would have to call it like foo(Float32(1.0)) which is annoying but by adding the Number overload it works the same except users can now also just do foo(1)

#

so I wanted the same for my vectors but it's not possible

#
foo(vec::Vector2f) = # ...
foo(vec::Tuple{T1, T2}) where {T1 <: Number, T2 <: Number} = foo(Vector2f(convert(Cfloat, vec[1]), convert(Cfloat, vec2[2])))
#

dong this for 70 functions that sometimes take 3 or more vectors will be so annoying

worn elk
#

Maybe have a single "format" function?

#

Also... some seems a bit overtyped.

worn elk
#

Then convert(Vector2f,i) can then be dispatched to converting both arguments to Cfloat.

#

format(x::Tuple{<:Number,<:Number}) = Vector2f(format(x[1]),format(x[2]))

#

@slate canopy
It seems you aren't familiar with multiple dispatch?

#

Have a single "format" function doing all the work here would be good.

lapis prairie
#

zamn

worn elk
#

format(x...) = [format(i) for i in x]

slate canopy
#

how is this differetn from just converting?

worn elk
#

You then dispatch on format later on.

slate canopy
#

I only need one method of it that convert a tuple to Vector2f

worn elk
#

And then you could do
foo(x...) = foo(format(x...)...)

slate canopy
#

oh you mean that I can use it for 1, 2, or 3 vectors

#

instead of writing convert 3 times

#

I understand

worn elk
#

Make a single format function that lets the dispatch do the work.

#

Yeah...

#

Not sure about type stability...

#

Oh...
@slate canopy
Use the () bracket.

#

Not the list bracket.

#

Type stability.