Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements exclusive to Scala 3.0 #785

Open
japgolly opened this issue Oct 8, 2020 · 4 comments
Open

Improvements exclusive to Scala 3.0 #785

japgolly opened this issue Oct 8, 2020 · 4 comments

Comments

@japgolly
Copy link
Owner

japgolly commented Oct 8, 2020

  • impurity safe zones using context functions
  • use opaque types to avoid allocations
  • intersection & union types to both avoid allocations, and better represent raw facades
  • use erased to remove compile-time-only constructs from JS output
  • mark any nullable types for explicit nulls
  • document changes

Done

@japgolly japgolly changed the title Add more compile-time safety in Scala 3 Improvements exclusive to Scala 3.0 Dec 22, 2020
@japgolly
Copy link
Owner Author

Excerpt from TriStateCheckbox:

  final case class Props(state       : State,
                         setNextState: Callback,
                         disabled    : Boolean = false)

  private def render($: ScalaComponent.MountedPure[Props, Unit, Unit], p: Props) = {
    val setNext = $.props.flatMap(p => p.setNextState.unless_(p.disabled)) // Only access .setNextState inside the Callback for Reusability
      ...
  }

  implicit val reusabilityProps: Reusability[Props] =
    Reusability.caseClassExcept("setNextState") // .setNextState is never accessed outside of a Callback

Scala 3 could allow something like this (and with erased classes, without incurring any runtime cost!):

  final case class Props(state       : State,
                         setNextState: Xxxxxxxxxxx[Callback],
                         disabled    : Boolean = false)

  private def render($: ScalaComponent.MountedPure[Props, Unit, Unit], p: Props) = {
    val setNext = $.props.flatMap(p => p.setNextState.unless_(p.disabled))
      ...
  }

  implicit val reusabilityProps: Reusability[Props] =
    Reusability.caseClass

where

  • Reusability[Xxxxxxxxxxx[A]] is Reusability.always
  • given [A] Conversion[Xxxxxxxxxxx[A], A](using InRenderFn | InCallback)
  • Callback methods like {apply,map,flatMap,etc} get InCallback ?=>
  • Render methods get InRenderFn ?=>

@japgolly
Copy link
Owner Author

japgolly commented Apr 26, 2021

Oh man, this is why it'd be good to enforce at the type-level. I just made a mistake above. Accessing the Callback in the render function would void Reusability (which is why I used $.props in the first place).

Correction:

given [A] Conversion[Xxxxxxxxxxx[A], A](using InRenderFn | InCallback)
// It should actually be this to preserve Reusability
given [A] Conversion[Xxxxxxxxxxx[A], A](using InCallback)

No wait a minute.... That's easily hacked:

def render(p: Props) = {
  val hack = Callback(p.setNextState) // wrong because `p` is fixed
}

How on earth can I have this work?

def render(p: Props) = {
  val good  = $.props.flatMap(_.setNextState)
  val bad  = Callback(p.setNextState)
}

I could just solve it really simplistically for the single BackendScope case but that feels a bit limited.

def render(p: Props) = {
  val good = $.fromProps(_.setNextState) // provide evidence directly from BackendScope
  val bad  = Callback(p.setNextState)    // reject because evidence unavailable
}

trait BackendScope[P, S] {
  // obviously rename all of this
  def fromProps[A](f: XxxxxxEvidence ?=> P => Xxxxxxxxxxx[A]): A
}

?

@japgolly
Copy link
Owner Author

Actually if I were to do something so simple, I wouldn't even need Scala 3 features. We could have this in Scala 2 today.

final case class Xxxx[A](unsafeGet: A)

trait BackendScope[P, S] {
  def fromProps[A](f: P => Xxxxxxxxxxx[A]): CallbackTo[A] =
    props.flatMap(f(_).unsafeGet)
}

@japgolly
Copy link
Owner Author

japgolly commented Jun 7, 2021

  • Remove runtime footprint
    • JsRepr
    • OptionLike for Option
    • Component builder
    • sourcecode (microlibs)
  • Make erased versions of <:< & =:= (microlibs)
  • Can comp-builder endo-fns be greatly simplified using the new polymorphic fns?
  • Undo the commit after 12c6a3e that reverts all the erased stuff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant