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

def in structural type is rejected, but val is accepted #1175

Closed
samuelgruetter opened this issue Mar 14, 2016 · 7 comments
Closed

def in structural type is rejected, but val is accepted #1175

samuelgruetter opened this issue Mar 14, 2016 · 7 comments

Comments

@samuelgruetter
Copy link
Contributor

object StructuralTypes {
  type A = { def foo: Int }
  type B = { val foo: Int }
}

dotty rejects this example:

[error] /home/sam/Documents/git/scalameta/tutorial/src/main/resources/StructuralTypes.scala:2: error: refinement method foo without matching type in parent Object
[error]   type A = { def foo: Int }
[error]                  ^
[error] one error found

scalac accepts it, and I guess dotty should as well?

@odersky
Copy link
Contributor

odersky commented Mar 14, 2016

We have not decided yet to what degree dotty will support this.

On Mon, Mar 14, 2016 at 2:48 PM, Samuel Gruetter notifications@github.com
wrote:

object StructuralTypes {
type A = { def foo: Int }
type B = { val foo: Int }
}

dotty rejects this example:

[error] /home/sam/Documents/git/scalameta/tutorial/src/main/resources/StructuralTypes.scala:2: error: refinement method foo without matching type in parent Object
[error] type A = { def foo: Int }
[error] ^
[error] one error found

scalac accepts it, and I guess dotty should as well?


Reply to this email directly or view it on GitHub
#1175.

Martin Odersky
EPFL

@olafurpg
Copy link
Contributor

If structural types will not be supported, I think we will need a good migration story for patterns where structural types are used as type classes.

For example, consider the Closeable structural type in better-files:

  type Closeable = {
    def close(): Unit
  }

The Closeable structural type is used to pimp unrelated types such as java.io.Closeable and scala.io.Source, like this

  implicit class CloseableOps[A <: Closeable](resource: A) {
    /**
      * Lightweight automatic resource management
      */
    def autoClosed: ManagedResource[A]
  }

The best rewrite I could come up with for this situation was changing Closeable to a type class and manually provide typeclass instances for each type.

trait Closeable[T] {
  def close(): Unit
}
object Closeable {
  // Note. `extends Closeable[java.io.Closeable]` is not correct because then
  // we lose the original type
  implicit object ZOSClose extends Closeable[ZipOutputStream] {
    override def close(e: ZipOutputStream): Unit = e.close()
  }
  // ... for every supported type
}

implicit class CloseableOps[A](resource: A)(implicit ev: CanClose[A])

Is there a better approach to rewrite the Closeable structural type? The approach above is bad for several reasons. Most importantly, it breaks the public api of better-files and boilerplate is required for each new supported type.

@smarter
Copy link
Member

smarter commented Aug 26, 2016

I don't think that the use of structural types here is a good idea, you shouldn't call close on something without knowing the semantics of close for that particular thing, java.io.Closeable documents the semantics of its close method and if scala.io.Source respects them then it should implement java.io.Closeable.

@odersky
Copy link
Contributor

odersky commented Aug 26, 2016

Ouch. I thought @soc had shown that nobody uses structural types!

If needed I believe the best strategy would be to just add them back, maybe under Scala-2 mode. Maybe there's some synergy to be had with applyDynamic, and maybe we can use DynamicInvoke for the implementation.

So, question: Can we write a "native" implementation of applyDynamic which uses the platform's reflection? cc @densh since this is probably hardest on Scala.native.

Edit: Talking to @sjrd it seems this is non-trivial even on JS. So probably just have a direct InvokeDynamic implementation.

@olafurpg
Copy link
Contributor

I don't think that the use of structural types here is a good idea

I agree. In addition, there is a performance penalty to pay at runtime. Structural are in general an anti-pattern, in my opinion. However, there is no denying that structural types are (by far) the most syntactically lightweight solution for this situation with Closeable.

If needed I believe the best strategy would be to just add them back, maybe under Scala-2 mode.

It would make migration at lot smoother where structural types are used.

An alternative solution would be to make the type class rewrite more syntactically lightweight, for example with automatic derivation of implicit instances. This could result in a net win on all dimensions.

@densh
Copy link

densh commented Sep 7, 2016

@odersky @soc Structural type is the only language feature we don't support at all on Native at the moment. It is indeed trickier to implement for us, given that both runtime and compiler need to have special support for the new kind of method dispatch. We'll revisit this issue once we have initial support for java.lang.reflect.* (scala-native/scala-native#159).

@smarter
Copy link
Member

smarter commented Jan 11, 2018

Closing, see #1886

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

5 participants