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

Opaque types implementation #504

Closed
adriaanm opened this issue May 10, 2018 · 18 comments
Closed

Opaque types implementation #504

adriaanm opened this issue May 10, 2018 · 18 comments

Comments

@adriaanm
Copy link
Contributor

implementation of https://docs.scala-lang.org/sips/opaque-types.html

will be available during the 2.13.x cycle under -Xsource:2.14. If all goes well, on by default in 2.14.0

@NthPortal
Copy link

Has the syntax been decided yet? The consensus to Martin's inline class idea wasn't clear to me

@adriaanm
Copy link
Contributor Author

I expect we'll go with the syntax from the SIP: opaque type Name = String

@adriaanm adriaanm added this to the 2.13.0-M5 milestone Jun 14, 2018
@adriaanm adriaanm changed the title opaque types implementation Opaque types implementation Jun 14, 2018
@adriaanm
Copy link
Contributor Author

Tentatively assigning to M5 to keep this on our radar. (I assume it won't be ready until after 2.13.0 final)

@adriaanm
Copy link
Contributor Author

Implementation note: one complication I hadn't considered so far is that baseTypeSeq is pre-computed, and I don't think we already have a mechanism to make sure abstract types in a BTS are treated in a context-dependent way. BTS works very differently in dotty, and would be hard to backport to scalac

@SethTisue SethTisue modified the milestones: 2.13.0-M5, 2.13.0-RC1 Aug 7, 2018
@adriaanm adriaanm modified the milestones: 2.13.0-RC1, 2.13.1 Aug 7, 2018
@SethTisue
Copy link
Member

@adriaanm are you still thinking of slipping this into a 2.13.x release under -Xsource:2.14, or is the new plan to do it in 2.14 only?

@milessabin
Copy link

slipping this into a 2.13.x release

Pretty please ...

@julienrf
Copy link

I expect we'll go with the syntax from the SIP: opaque type Name = String

What do you think of using a value class with a private constructor instead?

// Example taken from the current SIP
package object opaquetypes {
  opaque type Logarithm = Double

  object Logarithm {
    // These are the ways to lift to the logarithm type
    def apply(d: Double): Logarithm = math.log(d)

    def safe(d: Double): Option[Logarithm] =
      if (d > 0.0) Some(math.log(d)) else None

    // This is the first way to unlift the logarithm type
    def exponent(l: Logarithm): Double = l

    // Extension methods define opaque types' public APIs
    implicit class LogarithmOps(val `this`: Logarithm) extends AnyVal {
      // This is the second way to unlift the logarithm type
      def toDouble: Double = math.exp(`this`)
      def +(that: Logarithm): Logarithm = Logarithm(math.exp(`this`) + math.exp(that))
      def *(that: Logarithm): Logarithm = Logarithm(`this` + that)
    }
  }
}

Alternate syntax, using private constructors of value classes:

package object opaquetypes {
  class Logarithm private (private val value: Double) extends AnyVal {
    // This is the first way to unlift the logarithm type
    def toDouble: Double = math.exp(value)
    def +(that: Logarithm): Logarithm = Logarithm(math.exp(this.value) + math.exp(that.value))
    def *(that: Logarithm): Logarithm = Logarithm(this.value + that.value)
  }

  object Logarithm {
    // These are the ways to lift to the logarithm type
    def apply(d: Double): Logarithm = new Logarithm(math.log(d))

    def safe(d: Double): Option[Logarithm] =
      if (d > 0.0) Some(Logarithm(d)) else None

    // This is the second way to unlift the logarithm type
    def exponent(l: Logarithm): Double = l.value
  }
}

The benefit is that we don’t need to introduce a new keyword, we can use plain old methods instead of extension methods, and also, it makes the syntax more similar to value classes, which is a good thing in my opinion because these features are similar.

On the other hand, the statu quo has the advantage of having a syntax similar to “transparent” type aliases: defining an opaque type is just a matter of adding an opaque modifier in front of a type alias definition. Also, I’m not sure what’s the future of value classes, but if we are going to deprecate or not promote them, then it makes no sense to try having a similar syntax for opaque types.

@gabriel-bezerra
Copy link

I don't know if it has been considered in the SIP, but would it make sense to allow for type bounds in the opaque type definition?

opaque type Logarithm <: Double = Double

That would allow to use Logarithm where Double is expected, but not Double where Logarithm is expected.

@sjrd
Copy link
Member

sjrd commented Dec 11, 2018

What do you think of using a value class with a private constructor instead?

This was the very first design. It was rejected because that syntax is completely at odds with the semantics. Value classes are classes: they have a classOf, one can faithfully pattern-match on them, they can implement interfaces, etc. Basically value classes have all the semantics of classes, with the exception of identity.

Opaque types do not have any of these things. Their semantics are literally the same as (transparent) type aliases, with one exception: they do not participate in subtying relationships outside the companion object. So using the type alias syntax with a modifier is a much better fit for the specific semantics that they carry.

@He-Pin
Copy link

He-Pin commented Dec 16, 2018

Will this be backported to 2.12.x?

@adriaanm
Copy link
Contributor Author

adriaanm commented Dec 16, 2018 via email

@lJoublanc
Copy link

Will the opaque type keyword support type parameters? e.g. opaque type Timestamp[T <: TimeUnit] = Long?

@adriaanm
Copy link
Contributor Author

adriaanm commented Feb 8, 2019

Yes, see e.g. the immutable array example in the SIP: https://docs.scala-lang.org/sips/opaque-types.html#immutable-ie-write-once-arrays

@nafg
Copy link

nafg commented Jun 13, 2019

Now that 2.13.0 has been released, what's the current thinking on how long it is likely to be until this ships?

@adriaanm
Copy link
Contributor Author

I can see a way to support the self type encoding in 2.13 and support a subset of 3.0 opaque types in 2.14 (you’d have to be a bit more explicit inside the scope of the opaque type that your selecting the type member on this and not on the containing object). I can elaborate after scala days if you’re curious :) as soon as we’ve recovered from 2.13 and the conf, we’ll work on sharing and refining the 2.14 roadmap.

@szeiger szeiger modified the milestones: 2.13.1, 2.13.2 Sep 9, 2019
@SethTisue SethTisue modified the milestones: 2.13.2, 2.14 Feb 6, 2020
@strelec
Copy link

strelec commented Oct 17, 2021

So, will it happen?

@SethTisue
Copy link
Member

no, afraid not

@som-snytt
Copy link

What if we prefer the previous opaque reply?

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