Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Naden
@nadenf
Same as Map then .. that's great to hear. Thanks guys.
Markus Appel
@markusa380
@DmytroMitin I forgot to say thanks for your answer, that really helps to keep record type definitions tidy! :D
1 reply
Timofey
@GusevTimofey

Hi there!
I'm new with shapeless, so this question is possibly silly.
I have

case class Foo(foo1: String, foo2: String, foo3: String)

And I have a function which should take value from my class by field name

def getFoo(fieldName: String): String

I want to implement this function using shapeless, but I can't find a way to do this. If I write something like this:

val lens = LabelledGeneric[Foo].to(fooInstance)
lens.get(Symbol("foo1").witness)
lens.get(Symbol("foo2").witness)

it works fine, but I don't want to put foo1 and foo2 explicitly and want to do something like:

def getFoo(fieldName: String): String = lens.get(Symbol(fieldName).witness)
getFoo("foo1")

Is it a way to do this?

Paul Snively
@paul-snively
Yes. Parameterize getFoo by a type T, make the fieldName argument of type Witness.Lt[Symbol], and add an implicit argument list with a MkFieldLens for T and fieldName. You’ll then need to construct the lens from T and fieldName in the body and use it.
That is, you can construct a lens for T and a Witness.Lt[Symbol] given evidence that you can “make a field lens” for them.
Timofey
@GusevTimofey
@paul-snively do you mean getFoo should be like this?
def getFoo[T](fieldName: Witness.Lt[Symbol])(
  implicit mkF: MkFieldLens[Foo, Witness.Lt[Symbol]], mkT: MkFieldLens[Witness.Lt[Symbol], T]
): String
Paul Snively
@paul-snively
You only need one MkFieldLens, and the return type will depend on it.
Timofey
@GusevTimofey
@paul-snively I'm sorry, but I'm stuck with this
https://scastie.scala-lang.org/Gc3oaQkxQt6RLbXavjoIMg
Paul Snively
@paul-snively
Sorry, right: I’m saying “don’t make it Foo-specific.”
If you want it to be Foo-specific, just remove the T parameter, and change the second argument to MkFieldLens to fieldName.T.
I presume you’ll also want to take your Foo as an argument.
So something like getField(myFoo, ‘name).
Paul Snively
@paul-snively
What I described is an implementation where you don’t know or care what the type being looked up in is, so you’d parameterize the function by [T] and take a T as an argument too.
So the second argument to MkFieldLens is always going to be the singleton type of the field name. The first argument is going to be the type with the field (Foo, T, whatever).
Paul Snively
@paul-snively
MkFieldLens is both the evidence that you can make a lens into the named field of the type, and the mechanism for doing so. This is central to constructivist logic and the Curry-Howard isomorphism, but don’t focus on that for now.
I should add that it’s unusual to have a use-case where you want to look up a case class’s field by name, as opposed to just saying foo.bar. May I ask what problem you’re trying to solve?
Timofey
@GusevTimofey
In general, I'm trying to solve the case when I receive the field name of my case class in a String format from the outside, and I need to take this field's value from the model and do something with it.
I believe the last question is: how can I fix the error on 19 line
https://scastie.scala-lang.org/HkrAefAGTJeGXKb8pHgakg
Cause 'name syntax is deprecated
Timofey
@GusevTimofey

Btw, is it better to implement a match function for my problem? I thought about this, but the problem is that I have lots of fields in my model, and this function will be huge

def getFoo(name: String, foo: Foo): String =
  name match {
    case "foo1" => foo.foo1
    case "foo2" => foo.foo2
  }

Or shapeless here is good enough?

Paul Snively
@paul-snively
If by “from the outside” you mean “a String constructed at runtime,” i.e. not a constant, what you’re asking is impossible.
What you want instead is a Map.
That is, not a case class.
Fabio Labella
@SystemFw
you can do it with a case class, but it's still going to have Map semantics, i.e. it needs to return an Option
Paul Snively
@paul-snively
Right.
You can go from case class to extensible record, and from extendible record to Map, then back to extensible record and back to case class. But I’d just cut the gymnastics and use Map.
Fabio Labella
@SystemFw

You can go from case class to extensible record, and from extendible record to Map, then back to extensible record and back to case class

it should be slightly easier than that for just a get

but yeah fair enough
Paul Snively
@paul-snively
Maybe Map plus Typeable? Like half of what toMap etc. do?
Timofey
@GusevTimofey
ok, thanks a lot for help:)
Paul Snively
@paul-snively
Sure!
Tim Pigden
@TimPigden
Hi, apologies for cross-posting from magnolia but I might get a different audience here. This is actually an un-shapeless question. I've got a number of automatic typeclass derivation packages in my scala2 codebase. Originally, they were written in shapeless but got migrated to magnolia due to compilation speed issues. So what I was wondering, is what my best approach is to migration. If I were simply to completely rewrite using scala 3 new features is that going to do everything I want? Will it actually be better? And is Miles's talk from last year's ScalaDays (which I've just found) the best starting point - or is it out-of-date?
2 replies
Henry
@hygt
hello I'm trying to match over the type Foo[IO] => IO[_] (vs Foo[IO] => Any) using TypeCase and Typeable but I'm not going anywhere, is there a way?
Dmytro Mitin
@DmytroMitin
@hygt An instance of Typeable for functions would be unsound. How would you define it?
implicit def functionTypeable[X, Y](implicit castX: Typeable[X], castY: Typeable[Y]): Typeable[X => Y] =
  new Typeable[X => Y] {
    def cast(t: Any): Option[X => Y] =
      if (t == null) None
      else if (classTag[Function1[_, _]].runtimeClass isAssignableFrom t.getClass) {
        val f = t.asInstanceOf[Any => Any]
        // How to check that, for all x: Any, if x.cast[X].isDefined, then f(x.asInstanceOf[X]).cast[Y].isDefined?
        Some(f.asInstanceOf[X => Y])
      } else None
    def describe = s"${castX.describe} => ${castY.describe}"
  }
Ethan
@esuntag
@hygt Can you describe what you're actually trying to do here?
Henry
@hygt
I'm using MUnit to test an http4s app, which is pretty barebones (that's the selling point), and I wrote a bunch of helpers to test my routes, they take a block of assertions, and either return Unit or IO[Unit]
so basically I'm trying to figure out what is the T in block: Response[IO] => T
a TypeTag works but I wondered if there's a neater way to do it
Ethan
@esuntag
And here T should be either Unit or IO[Unit]?
Henry
@hygt
yes exactly (at least for now)
Ethan
@esuntag
Any reason you can't just have block: Unit and blockF: IO[Unit] separately as needed?
rnd4222
@rnd4222_gitlab
Is there plans on improving typeable from shapeless3 on dotty? Despite using tasty reflection, it still relies on ClassTags and (if I understand correctly) doesn't allows arbitrary types as case class fields
Naden
@nadenf
Hey anyone know if it's possible to get all of the values out of a HMap if I have a list of keys and the implicits in scope ?
Geovanny Junio
@geovannyjs

Hi guys!

I have a Poly1 that has a typeclass constraint, I found out that I can use LiftAll.instances to provide all the typeclasses instances, but I don't know how to provide the LiftAll.instances to the Mapper that is handling the Poly1.

Someone can shed some light?

Geovanny Junio
@geovannyjs
I already found out a solution: I can zip the LiftAll.instances with my HList and do a { case (t, enc) => enc.encode(t) } inside the map.
Duncan Hills Coffee Company
@DuncanHills
hey folks, I have a record and another HList that is guaranteed to be the same length as my record. I want to map the keys of the record to the values of the second HList. What's the easiest way to do that (I understand how to use shapeless pretty well already). I know about Keys to get the records keys, but how would I zip them with the second HList as values to produce a new record?
basically I want the field names of the original record with new values from the second HList.
Duncan Hills Coffee Company
@DuncanHills
aha, I think I found it. ZipWithKeys
Gabriel Volpe
@gvolpe

I have the following piece of code that compiles just fine:

sealed trait Yay
object Yay {
  @newtype case class MyId(value: java.util.UUID)

  case class Foo(x: Int) extends Yay
  case class Bar(y: Yay.MyId, z: String) extends Yay
}

Check[Yay]

However, if I define Bar as (y: MyId) instead of Yay.MyId, it no longer compiles. Here is the implementation of Check, originally written by Fabio.

The @newtype annotation comes from https://github.com/estatico/scala-newtype

Anyone has experience combining type-level machinery with newtypes that could help? I nailed it down to this minimal example but would definitely appreciate another pair of eyes. Thanks in advance!

Gabriel Volpe
@gvolpe
Here's a Scastie, should make it easier: https://scastie.scala-lang.org/6TZGnRWIRDCBQxYDPOYreA
Ethan
@esuntag
Hm... Maybe something with macro execution order?