can i instantiate `class Foo` from `Foo::class` in...
# getting-started
h
can i instantiate
class Foo
from
Foo::class
in any way?
s
Yes… but that’s rarely what people need
unless you’re, like, doing serialization stuff
there are also usually like, a million caveats to keep in mind
h
so can you think of a better way to structure this:
object Metre : Unit("m", Length::class)
ergo, when you want to construct a quantity with the unit
Metre
it will construct a quantity of
Length
s
I feel like I’m missing context necessary to properly judge, but, what if you had like, a
Quantity
enum w/
LENGTH, MASS, TIME
etc
should units even be instanced? what are you really looking to describe here?
h
the unit, and then you can create a quantity of the appropriate type with just a number and a unit
I'll think through my approach a bit more
s
👍
an important thing to keep in mind is that there is no way to enforce constructor signatures vis a vis interfaces or abstract classes
h
which is a fucking shame
even though the invoke operator exists
s
I mean, invoke is there but, like, it’s not a constructor and isn’t expressly intended to replace constructors
h
yeah, but it can reliably mimic them
s
it’s times like these where I almost wish you still needed
new
to instantiate stuff
💯 1
almost
😛
h
i'd only want
new
if we also had
delete
d
object Metre : Unit("m", ::Length)
?
h
... does that work? i'll try it
d
Probably with
abstract class Unit(name: String, ctor: (Int) -> Value)
. I'm not sure what your constraints are or what your classes look like.
👆 2
h
appears to work like a charm. thank you @Dominaezzz
d
No problem!
h
I am so utterly skeptical this will work:
Copy code
abstract class Unit(name: String? = null, override val symbol: String, val quantities: List<KFunction1<Double, Quantity<*>>>) : Named,
    Symbolic {
    constructor(symbol: String, vararg quantities: KFunction1<Double, Quantity<*>>) : this(null, symbol, quantities.toList())
    override val name: String = name ?: javaClass.simpleName.insertSpaces()

    open val Double.toSIValue get() = this
    
    inline operator fun <Q: Quantity<Q>, reified K: KFunction1<Double, Quantity<Q>>> invoke(value: Double): Quantity<Q> {
        val constructor: K = quantities.first { it::returnType is K } as K
        return constructor(value.toSIValue)
    }
}
But we're gonna find out!
d
I have some serious doubts about that cast but let's see where this goes.
👆 1
h
yeah, and i also doubt this is the best way to go about it all
d
Copy code
abstract class Unit(
    override name: String = javaClass.simpleName.insertSpaces(),
    override val symbol: String,
    val quantities: Map<KClass<out Quantity>, KFunction1<Double, Quantity<*>>>
) : Named, Symbolic {
    constructor(symbol: String, vararg quantities: Pair<KClass<out Quantity>, KFunction1<Double, Quantity<*>>>) : this(symbol = symbol, quantities.toMap())

    open val Double.toSIValue get() = this
    
    inline operator fun <Q: Quantity<Q>, reified K: KFunction1<Double, Quantity<Q>>> invoke(value: Double): Quantity<Q> {
        val constructor: K = quantities[Q::class] as K
        return constructor(value.toSIValue)
    }
}
That won't compile as is but you get the idea.
h
yeah, probably best to create a map like that, but I wanted to make it easy as possible to create `Unit`s, so didn't want them to have to pass both a
KFunction1<Double, Quantity<*>>
and a
KClass<Quantity<*>>
but!
i could just have the map be built by referencing the return type
d
Yeah, if you make a DSL.
h
I'm just not too experienced with kotlin reflection
d
Ooh, you could potentially achieve
Unit("m", quant(::Length), quant(::Width))
, with
inline fun <reified Q: Quantity<Q>, reified K: KFunction1<Double, Quantity<Q>>> quant(k: K): Pair<KClass<Q>, K> = Q::class to k
.
(I think I'm enjoying this too much.)
h
hahaha
wanna see the whole project?
it's not much atm
d
Aha, don't tempt me.
Yeessss!!!
h
let me get it on github here in a sec
d
Thanks! I'll probably nitpic here and there 😅 .
h
Please do, I'd like to know if there are better ways to write in this language
or just structure the project as a whole. also probably best to switch to DM
d
Yeah
h
there already exists an extensive units of measurement library for java, as well as a kotlin port, but it lacks in a lot of ways that i'd want to implement
the reason I have multiple quantities per unit is for cases such as the
Newton
, which can measure
Force
or
Weight
but if i'm being honest, force and weight are actually the same thing, so I might just scrap multiple possible quantities per unit
that would fix a lot of problems 😮
d
Yeah. I'm currently trying to digest
Dimension
.
h
Okay, I can explain it
there are 7 base physical dimensions to reality
d
🤯
h
Length, Mass, Time, ElectricCurrent, Temperature, Amount of Substance, and Luminosity
all other dimensions can be expressed as a product of those raised to some power
d
Oh, the base quantities. I did those in A Level Physics.
h
so Area is Length to the power of 2
Acceleration is Time to power of -2
Force is Mass to power of 1 times Time to the power of -2
so Force is M = 1, L = -2
i hope this is making sense
d
Yeah
h
a quantity is the actually measurement. it quantifies within some kind of dimension
and the units are basically just a scalar
the 7 base dimensions map to the 7 base SI units from which all other SI units are derived
d
Yeah, it makes a lot of sense.
h
annoyingly the base unit for mass is the KILOgram instead of the gram -_-
d
lol
h
so one of the things that the Java library really lacks is unit and quantity conversions
you can't do something like
5.metre / 10.sec
and get back a quantity in
Velocity
and i think that the way I'm implementing
Dimension
is going to make that process really efficient
there's a one to many relationship between dimensions and quantities, because you can quantify the M=1, L=-2 dimension with
Force
or
Weight
as I mentioned above
and so there's a many to many relationship between Quantities* and Units
and then finally a one to many between Dimensions and Units
so i'm thinking i should probably set alternate quantities and units aside for the moment and focus on a 111 relationship
d
Hmm, weight isn't a quantity I guess?
l
In the new Jetpack compose library, i saw something along the line of unit conversion (but about pixels and stuff, not IRL units), and it mostly uses extension functions instead of OOP, which for me makes more sense, you might want to check it out https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/ui/core/src/main/java/androidx/ui/core/Dp.kt A very rough idea of what it might look like for IRL unit conversion: https://pl.kotl.in/kIZ_7N1u0
✍️ 1
h
yeah, the idea is you can do stuff like this:
Copy code
val distance = 1.kilo.metre
val speed = 3.kilo.metre / 1.hour // converts to Velocity
println(speed == 40.kph) // true
println(distance == 1.km) // true
println("duration: ${distance / speed}") // 20 minutes
l
h
yeah, but i'm making it all very generalized
so it can be a DSL, and also to avoid having to make a case by case conversion
b
for your original question, would it not make sense to have
Length
derive from
Unit
, and then
Metre
derive from that? so
Metre
doesn't need to dynamically provide a sub-type to unit, it's there in the class hierarchy?
h
But length isn't a unit? Maybe I'm confused
b
🤦 ha, true, i think i thought right past that