scala-records / scala-records

Labeled records for Scala based on structural refinement types and macros.
BSD 3-Clause "New" or "Revised" License
159 stars 14 forks source link

Open question: How to handle field name clashes when merging records #119

Closed cvogt closed 9 years ago

cvogt commented 9 years ago

so one feature I have in compossible is merging of records

val r_a: Record[{def name: String; def age: Int}] = Record(name="Chris") ++ Record(age=99)

this becomes a problem when field names overlap

val r_b: Record[{def age: Long; def age: Int}] = Record(age=101L) ++ Record(age=99)

which is a valid Scala type. Preventing these cases when implementing ++ as a macro isn't really viable, if this use case should be supported:

def merge[T,S](r1: Record[T], r2: Record[S]): Record[T with S] = r1 ++ r2

because here ++ can't know if T and S have name clashes. We can't statically check during lookup either:

def lookup[T](r: Record[T with {def age: Int}]) = r.age
lookup(merge(r_b))

we can't know if T contains another def age.

So how should we handle that?

One idea would be not only looking up values by field name, but also by type after that. But TypeTags are expensive and do not have referential equality. The latter may not be a problem. Using Fully Qualified names instead would break with path dependent types.

And how should we handle upcasting in this case?

val r: Record[{def age: Any}] = Record(age=101L) ++ Record(age=99)
r.age

I don't have good answers to these. The best course of action to me right now seems to be deciding on the "best" out of the bad potential behaviors we can think of and well document these.

For example

Alternative 1 (sound, but probably impractical):

Alternative 2 (unsound):

Alternative 3 (sound(?), but runtime exceptions in cases that would pass in 2, but also cases that would be just wrong in 2):

Any better suggestions? Any preferences? I have a slight tendency towards 3. Pushing people to avoid name clashes altogether and fail early and clearly even if at runtime seems better than making them work almost always. If we ever get faster type tags e.g. using scala meta (cc @xeno-by) we may be able to switch to Alternative 1.

gzm0 commented 9 years ago

Please use the already existing ticket for discussions (#104). I will continue there.