Beginner questions #525
-
Hi - Also - it is not obvious (to a beginner) from the documentation exactly how Coulomb is intended to be used to represent actual values. In my application, I have several things that might be measured in metres, for instance, and I want these all to be different types. I have tried, for instance, Also - is there any way to simplfy the declaration of types so I can write something like "val x:Wavelength = Wavelength(5)" or is this just a question of writing type aliases and methods by hand? sorry if these quesions are naive - hopefully they might be useful documentation for others facing the same beginner issues. |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 16 replies
-
I'm not Coulomb's author but I have used it a fair bit. My take on "how
Coulomb is intended to be used to represent actual values":
Replace
opaque type Wavelength=Quantity[Double,Metre]
with
type Wavelength=Quantity[Double,Metre]
opaque types are for very specific situations and this isn't one of them.
…On Sat, Nov 4, 2023 at 12:55 AM Joshua Portway ***@***.***> wrote:
Hi -
Could you clarify - does coulomb work entirely at compile time, so that at
runtime the resulting values can be unboxed primitives? It seems to be
architected to make that possible, but I am not sure from the documentation.
Also - it is not obvious (to a beginner) from the documentation exactly
how Coulomb is intended to be used to represent actual values. In my
application, I have several things that might be measured in metres, for
instance, and I want these all to be different types. I have tried, for
instance, opaque type Wavelength=Quantity[Double,Metre] - but this won't
work because the type classes for Coulomb don't resolve any more. Should I
be defining my own DerivedUnit for Wavelength? Or maybe using value
classes? Would the value classes remain unboxed (assuming coulomb values
themselves are unboxed)?
Also - is there any way to simplfy the declaration of types so I can write
something like "val x:Wavelength = Wavelength(5)" or is this just a
question of writing type aliases and methods by hand?
sorry if these quesions are naive - hopefully they might be useful
documentation for others facing the same beginner issues.
—
Reply to this email directly, view it on GitHub
<#525>, or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAXJZHV7ZSG55D2MW5BMELYCTZVPAVCNFSM6AAAAAA64PEB32VHI2DSMVQWIX3LMV43ERDJONRXK43TNFXW4OZVHAYDSMJTG4>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
type Wavelength = Quantity[Double, Meter]
type Depth = Quantity[Double,Meter] @jportway What semantic are you trying to capture here? I ask because there are some subtleties relating to the difference between a "unit" and an "abstract quantity" or "physical quantity" - for example "meter" is one unit representing the physical quantity of "length" Your types above seem like you might be trying to capture abstract quantities, but I am not sure. In |
Beta Was this translation helpful? Give feedback.
-
Hi Erik - thanks for taking the time to write such a considered answer. The value classes work, but there is considerable overhead introduced due to a lot of boxing and unboxing that goes on, so my hope was that I could build a similar type of system of types using Coulomb that would compile down to primitive types (given your link above it looks like this isn't currently acheivable). Type safety is important to me partly because I'm writing this code so that i can experiement freely with the system later without worrying about whether what I'm doing is valid (I'm not an expert in this domain) - and after exploring Coulomb a bit I'm impressed by the elegance of it so I'm keen to explore whether it could fit, or where i could use it in the future. Can you explain why you don't think just representing these values as derived units (or indeed, maybe as base units) is a good idea? It seems to be working, at least in part, for me so far. The only issues I've really had so far are :
What other problems am I likely to run into using this approach ? |
Beta Was this translation helpful? Give feedback.
-
OK, so here is a prototype concept: In operation it looks like this: scala> import coulomb.*, coulomb.syntax.*, coulomb.scoped.*, coulomb.testunits.{*, given}, coulomb.test.{*, given}, algebra.instances.all.given, coulomb.ops.algebra.all.given, coulomb.policy.standard.given, scala.language.implicitConversions
scala> val d1 = Depth(1d.withUnit[Meter])
val d1: coulomb.test.Depth[Double, coulomb.testunits.Meter] = coulomb.test$given_ScopedQuantityConstructor_Depth$$anon$1@369d5736
scala> val d2 = Depth(1d.withUnit[Yard])
val d2: coulomb.test.Depth[Double, coulomb.testunits.Yard] = coulomb.test$given_ScopedQuantityConstructor_Depth$$anon$1@1cb20b87
// adding with convertible units works
scala> (d1 + d2).quantity
val res0: coulomb.Quantity[Double, coulomb.testunits.Meter] = 1.9144
// good: this is an error, seconds are not a length
scala> val d3 = Depth(1d.withUnit[Second])
-- Error: ----------------------------------------------------------------------
1 |val d3 = Depth(1d.withUnit[Second])
| ^
| unit type Second not convertable to Meter
|----------------------------------------------------------------------------
scala> val w1 = Wavelength(1d.withUnit[Meter])
val w1: coulomb.test.Wavelength[Double, coulomb.testunits.Meter] = coulomb.test$given_ScopedQuantityConstructor_Wavelength$$anon$2@1089bfb9
// this should be a type error
// LOL this crashed the compiler, which is like a kind of type error
scala> d1 + w1
java.lang.AssertionError: assertion failed while typechecking rs$line$6
[error] java.lang.AssertionError: assertion failed
[error] at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:11)
[error] at dotty.tools.dotc.ast.tpd$.TypeApply(tpd.scala:60)
[error] at dotty.tools.dotc.ast.tpd$TreeOps$.appliedToTypeTrees$extension(tpd.scala:985) So, this isn't quite as clean as I'd like, but I think I can automatically instantiate Probably You can see above that my attempt to add a Depth with a Wavelength failed (which is good!) but instead of failing with a type error I literally crashed the compiler (lol not great!) |
Beta Was this translation helpful? Give feedback.
-
I think I hit the same crash, in Coulomb based code. Some case they didn't
expect, but Stucki fixed it. And the error output wil be improved in a
future version toio.
scala/scala3#16861 (comment)
…On Mon, 6 Nov 2023, 3:27 am Erik Erlandson, ***@***.***> wrote:
@armanbilge <https://github.com/armanbilge> lol check out the compiler
crash above 🤣
—
Reply to this email directly, view it on GitHub
<#525 (reply in thread)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAXJZA2RIIF2P7BNA5TFCDYC646BAVCNFSM6AAAAAA64PEB32VHI2DSMVQWIX3LMV43SRDJONRXK43TNFXW4Q3PNVWWK3TUHM3TIOBQGEZDK>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
@jportway I started a pull request for doing efficient collections: #530 It defines a scala> import coulomb.*, coulomb.syntax.*, coulomb.units.si.{*, given}, coulomb.collection.immutable.*
scala> val qv = QuantityVector(1f.withUnit[Meter], 2f.withUnit[Meter])
val qv:
coulomb.collection.immutable.QuantityVector[Float, coulomb.units.si.Meter] = QuantityVector(1.0, 2.0)
scala> qv.values
val res0: Vector[Float] = Vector(1.0, 2.0)
scala> qv(0)
val res1: coulomb.Quantity[Float, coulomb.units.si.Meter] = 1.0 |
Beta Was this translation helpful? Give feedback.
I'm not 100% convinced this is a thing coulomb should officially support. It raises at least as many questions as it answers. For example, what, if any, definition is there for
Depth * Wavelength
- these types are not closed under multiplication, power, etc.If all you want is to properly distinguish Depth from Wavelength, then standard case classes are arguably sufficient: