I’m use to create Value Object with only 1 value just to add type & have safer code (for example having typed ID prevent from passing wrong parameter).
actual
class People(val id:PeopleId, ...) //for the example
class PeopleId(val value:String)
class ContractId(val value:String)
fun findContract(id:ContractId):Contract? = ...
val people = People(PeopleId("peopleId")) // wrapping feels too verbose... especially when heavy used
findContract(people.id) // this does not compile, that's pretty much the goal
But there’s a minor problem with the heap, wrapping is noisy and class declaration is noisy too
Proposal :
pseudotype
.(or… inlinetype
or whatever keyword feels better) (this is not inspired from css )
first the example
class People(val id:PeopleId, ...)
pseudotype PeopleId = String
pseudotype ContractId = String
fun findContract(contract:ContractId):Contract? = ...
val people = People("peopleId") //good, no noise
findContract(people.id) //this does NOT compile
explanation :
- looks like typealias, does not affect runtime
- like typealias a pseudotype can be assigned from/to its inline type. this means
People("peopleId")
,val id:PeopleId = "peopleid"
orval x:String = people.id
are ok. (this also meansfindContract(people.id as String)
would compile… but c’mon!) - unlike typalias a pseudotype can only be assigned from/to its inline type and NOT from other pseudotype:
findContract(people.id)
will not compile then.
edit:
after answering to first answer I found that maybe this proposal could also be considered as an evolution of typealias
:
- we can consider this as a problem that is more about assigning a typealias to another
- so:
- first generating a warning when assigning a typealias to another
- then transforming this warning to an error
this would do the trick… And it’s even better : no keyword added, still the casting (as typealias2
) workaround to compile old code
Actual not working solution 1 : typealias
typealiases don’t prevent type error, they are just (guess what…) alias not answering my need (and not intended to).
class People(val id:PeopleId, ...) //for the example
typealias PeopleId = String //good, no noise
typealias ContractId = String
fun findContract(contract:ContractId):Contract? = ...
val people = People("peopleId") //good, no noise
findContract(people.id) //this compile & this is why typealias is "too weak" for this need
Incoming not working solution 2 : inline class
Today I saw inline class (I think this concept comes from scala… not sure). They seems very powerfull… But overkill for my need & does not solve the need (once again, it’s not intended to… I think).
class People(val id:PeopleId, ...) //for the example
inline class PeopleId(val value:String) //even more verbose...
inline class ContractId(val value:String)
fun findContract(id:ContractId):Contract? = ...
val people = People(PeopleId("peopleId")) // still too verbose
findContract(people.id) // inline fix the heap problem... But only it
Honnestly I’m quite surprise this need is not elegantly covered by kotlin (which is meant to be pragmatic).
What do you guys (edit: and girls ) think ?