Skip to content

4. Porting

Giuseppe Barbieri edited this page Aug 7, 2017 · 6 revisions

4.1 Naming

Since i32vec2 would have been I32vec2 because java requires always first letter capital, it has been decided to move the type part at the right and changing the bit lenght directly with the primitive data type (Vec2i32 would have been confusing), so we simply have Vec2i.

c++ java
bvec* Vec*bool
dvec* Vec*d
vec* Vec*
i8vec* Vec*b
i16vec* Vec*s
i32vec* Vec*i
i64vec* Vec*l
u8vec* Vec*ub
u16vec* Vec*us
u32vec* Vec*ui
u64vec* Vec*ul
dmat* Mat*d
mat* Mat*

* means 1, 2, 3 or 4 for c++, but on java only 2, 3 and 4 because we didn't port any *vec1 for the moment since there is no apparent reason.

4.2 Instantiation

All plain functions (that is without an ending underscore *_) will always create a new instance.

This means, for example, that in a case like this:

val a = Vec2(0, 1)
val b = Vec2(2)
val c = a + b
Vec2 a = new Vec2(0, 1);
Vec2 b = new Vec2(2);
Vec2 c = a.plus(b)

a and b won't be modified by the addition and a new instance will be assigned to the variable c.

On contrary, in this case:

val a = Vec2(0, 1)
val b = Vec2(2)
a plus_ b
Vec2 a = new Vec2(0, 1);
Vec2 b = Vec2(2);
a.plus_(b)

the result of the addition will be saved into the receiver object a, modifying it. You can think of plus_ as +=.

There are a couple of reasons for this design:

  • coherence with the kotlin convention, that indicates to create a new instance with operator overloading
  • it makes the code less error prone, in the worst case scenario, if it wasn't intended to be like that, you'll "waste" an allocation, but there won't be any logic bug, your program won't crash or behave abnormally. Thus, if you want to avoid a new allocation and save the result into the receiver object, you can have it, but you have to ask for it explicitly, and it does not appear out of the blue.
  • it makes the code easier and natural to read

Normally, the resulting object is always returned, (Vec2 in this case) in order to give the possibility to concatenate multiple operations in cascade.

All the operational calls are contained under the Companion object of the given class, that means Vec2.plus(..) for Kotlin, Vec2.Companion.plus(..) for Java. However, to improve usability, each vec/mat class have its own functions (they will refer always to the static ones though).

Note that binary operations involving a scalar are obviously supported, but if you want to perform:

1f - Vec2(3f, 4f)

in Kotlin you can type:

val a = 1f - Vec2(3f, 4f)

in Java:

Vec2 a = Vec2.Companion.minus(1f, new Vec2(3f, 4f));

4.3 Notes

Since java transforms byte and short value to int before doing any operation, it is provided the same for classes involving those type, signed or unsigned.

Kotlin offers the possibility to infix calls with only one argument. All the suitable call (and when it made sense) exploits this feature. For example:

val a = Vec3(0)
val b = Vec3(1, 2, 3)
val c = a cross b
Clone this wiki locally