Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Oct 26 20:58
    julien-truffaut synchronize #929
  • Oct 26 20:58

    julien-truffaut on dot-lens-syntax

    format (compare)

  • Oct 26 20:48
    julien-truffaut review_requested #929
  • Oct 26 20:48
    julien-truffaut review_requested #929
  • Oct 26 20:48
    julien-truffaut opened #929
  • Oct 26 20:45

    julien-truffaut on dot-lens-syntax

    WIP add .lens syntax to Lens an… (compare)

  • Oct 26 17:19

    julien-truffaut on filter

    add filter (compare)

  • Oct 23 01:19
    cquiroz commented #925
  • Oct 22 19:43
    julien-truffaut commented #925
  • Oct 22 19:43
    julien-truffaut reopened #925
  • Oct 22 19:32

    julien-truffaut on master

    Crosscompile core to dotty (#92… (compare)

  • Oct 22 19:32
    julien-truffaut closed #928
  • Oct 22 19:32
    julien-truffaut closed #925
  • Oct 22 19:32
    julien-truffaut commented #928
  • Oct 22 15:25
    cquiroz opened #928
  • Oct 22 13:21
    cquiroz assigned #925
  • Oct 22 07:20
    julien-truffaut commented #913
  • Oct 22 07:19
    julien-truffaut edited #927
  • Oct 22 07:19
    julien-truffaut edited #927
  • Oct 22 07:18
    julien-truffaut edited #913
nafg
@nafg
Basically I could make an intermediate data type that more cleanly separates the two things
So in addition to the original form, (fullAddressString, areaString),
there is another form, ((fullAddressString, computedAreaString), explicitlyProvidedAreaString)
Then, I could make a lens from the first for to the second
where get sets computedAreaString to either nothing or areaString, not sure if it matters, and explicitlyProvidedAreaString to areaString. It might be an Option type in which case "" becomes None
And set will set areaString to either explicitlyProvidedAreaString if it is defined, otherwise computedAreaString
and of course fullAddressString to its namesake
nafg
@nafg
Then I can "zoom" the original state to the more-cleanly-separated state, and then the UI can easily map each field of the tuple to a separate bit of UI
Julien Truffaut
@julien-truffaut
I am not entierly sure I follow, if you could make a gist it would be very useful.
nafg
@nafg
@julien-truffaut which part?
I haven't written it yet, I just thought of it now
The UI abstraction isn't the point, you can ignore that really
I guess the lens bit would be something like
    case class Original(full: String, area: String)
    case class SimplifiedGeoAddress(full: String, areaFromGeoAddress: String)
    case class Separated(simplied: SimplifiedGeoAddress, explicitArea: String)
nafg
@nafg
val get: Original => Separated = original => Separated(SimplifiedGeoAddress(original.full, original.area), original.area)
val set: Separated => Original => Original =
  s => o =>
    Original(s.simplified.full, s.explicitArea.trim match { case "" => o.area  case a => a })
val lens = Lens(get)(set)
val tupleIso: Iso[Separated, (SimplifiedGeoAddress, String)] = GenIso.fields[Separated]
val separatedState = originalState.zoomStateL(lens)
val addressAutocompleteState: StateSnapshot[SimplifiedGeoAddress] = separatedState.zoomStateL(fields.first)
val areaTextFieldState: StateSnapshot[String] = separatedState.zoomStateL(fields.second)
nafg
@nafg
The actual code would be slightly different since it would use something slightly different from StateSnapshot but that's not important
What's important is now the address autocomplete UI doesn't need to worry about when to overwrite the actual area field; it always sets areaFromGeoAddress, unconditionally
And of course the area input only deals with the String and string setter that update explicitArea
The concern of when to overwrite the area field is handled at a higher layer, in val lens above
I called it SimplifiedGeoAddress because it's a simplified version of what the TomTom API actually returns, which I model like this:
case class Address(streetNumber: Option[String],
                   streetName: Option[String],
                   municipality: Option[String],
                   countrySecondarySubdivision: Option[String],
                   countrySubdivision: Option[String],
                   countrySubdivisionName: Option[String],
                   postalCode: Option[String],
                   extendedPostalCode: Option[String],
                   countryCode: String,
                   country: String,
                   countryCodeISO3: String,
                   freeformAddress: String,
                   localName: Option[String])
nafg
@nafg
I can't construct one of those from Original so I need a diluted version of it so I can go in both directions
Julien Truffaut
@julien-truffaut
What do you think of this idea? I think it could make the API much nicer to use and more beginner friendly: optics-dev/Monocle#929
nafg
@nafg
It's nice but doesn't it result in much more work?
Julien Truffaut
@julien-truffaut
on library side, yes, lots of boiler plate.
But if it simplifies lots of user code, I will say that's worth it.
Maybe they are ways to generalise this pattern but I am not knowledgable about macros, I just copy/paste and tweak them.
nafg
@nafg
I mean more runtime work, or more compile-time work because of more macro invocations
Julien Truffaut
@julien-truffaut
if it does require more work, it will be at compile time, I believe
nafg
@nafg
Doesn't it have to instantiate a new Lens and new functions each time?
Julien Truffaut
@julien-truffaut
ah yes but I assume that's already the case nowadays when someone does GenPrisn[Foo, Bar] composeLens GenLens[Bar](_.buzz)
ritschwumm
@ritschwumm
@julien-truffaut how about .lens.foo instead of .lens(_.foo) ?
nafg
@nafg
@julien-truffaut but that would usually be done in a val in the companion no?
@ritschwumm how would you implement that?
Julien Truffaut
@julien-truffaut
@ritschwumm it would be nice but it would require dynamic, so no completion
ritschwumm
@ritschwumm
yeah, dynamic. for intellij you could probably make completion work, but not in general.
Julien Truffaut
@julien-truffaut
@nafg yeah you can still do it this way, but the goal of this PR is more to lower the entry barrier.
nafg
@nafg
sure
Julien Truffaut
@julien-truffaut
But you're right we should watch the performance impact (not sure how to do it) because it might result in slow down when its often used.
nafg
@nafg
What about the version for dotty? Didn't that have something similar?
Julien Truffaut
@julien-truffaut
ah yes, we can do much better in Dotty
At first, I wanted to do a big rewrite for dotty and do lots of UX improvments. But we need more time to work on the new optic encoding, so I don't want to postpone those low hanging fruits.
Current API is too difficult for beginners and it doesn't require too much work to make it more friendly, e.g. optics-dev/Monocle#908
ritschwumm
@ritschwumm
in my lenses, each optic composes only with an optic of the same type (with a symbolic operator >=>, but i have conversion methods from one type to another. i found that easier to handle.
someLens.toOptional >=> Optional.some >=> somePrism.toOptional

and (completion be damned) i always have (manually written)

object Foo {
  val L = Lens.Gen[Foo]
}
final case class Foo(bar:Int, quux:String)

so i can use e.g.
Optional.some >=> Foo.L.quux

not that i'm happy with that, either :)
Julien Truffaut
@julien-truffaut
@ritschwumm Yeah they are lots of trade off