简体   繁体   中英

'with' keyword usage in scala with case classes

I though if something like this makes sense in scala:

object CaseClassUnion extends App {
  case class HttpConfig(bindUrl: String, port: String)
  case class DbConfig(url: String, usr: String, pass: String)

  val combined: HttpConfig with DbConfig = ???
  
  //HttpConfig("0.0.0.0", "21") ++ DbConfig("localhost", "root", "root") 
  //would be nice to have something like that
}

At least this compiles... Is there a way, probably with macros magic to achieve union of two classes given their instances? In zio I believe there is something like in reverse:

val live: ZLayer[ProfileConfiguration with Logging, Nothing, ApplicationConfiguration] =
ZLayer.fromServices[ProfileConfigurationModule.Service, Logger[String], Service] { (profileConfig, logger) =>  ???

where we convert ProfileConfiguration with Logging to function of ProfileConfigurationModule.Service, Logger[String] => Service

Several things.

When you have several trait s combined with with Scala does a trait linearization to combine them into one class with a linear hierarchy. But that's true for trait s which doesn't have constructors!

case class (which is not a trait) cannot be extended with another case class (at all) because that would break contracts like:

case class A(a: Int)
case class B(a: Int, b: String) extends A(a)

A(1) == B(1, "") // because B is A and their respective fields match
B(1, "") != A(1) // because A is not B
B(1, "").hashCode != A(1).hashCode // A == B is true but hashCodes are different!

which means that you cannot even generate case class combination manually. You want to "combine" them, use some product: a tuple, another case class, etc.

If you are curious about ZIO it:

  • uses traits
  • uses them as some sort of type-level trick to represent an unordered set of dependencies, where type inference would calculate set sum when you combine operations and some clever trickery to remove traits from the list using .provide to remove dependency from the set
  • ZLayers are just making these shenanigans easier

so and if you even pass there some A with B you either combined it yourself by using cake pattern, or you passed dependencies one by one. ZIO developer might never be faced with the problem of needing some macro to combine several case classes ( .provide(combineMagically(A, B, C, D, ...) ) as they could pass implementations of each dependency one by one ( .provide(A).provide(B) ) and the code underneath would never need the combination of these types as one value - it's just a compile-time trick that might never translate to the requirement of an actual value of type A with B with C with D... .

TL;DR: You cannot generate a combination of 2 case classes; ZIO uses compound types as some sort of type-level set to trace dependencies and it doesn't actually require creating values of the compound types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM