This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Trac #4506: structural types vs. no-arg defs

2 replies
Todd Vierling
Joined: 2011-04-27,
User offline. Last seen 42 years 45 weeks ago.
https://lampsvn.epfl.ch/trac/scala/ticket/4506#comment:2

I'm not sure why the close comment on this issue directed me to http://lampsvn.epfl.ch/trac/scala/changeset/24029, and I'm thinking that perhaps what I was asking wasn't really clear. In any case, here's a code example of the issue, and I've changed it to be more like the case reported in https://lampsvn.epfl.ch/trac/scala/ticket/2810 so that a concrete use case can be understood:

object Test {
  type CloseableLikeNoParams = { def close: Unit }  type CloseableLikeEmptyParams = { def close(): Unit }
  def doCloseNoParams(x: CloseableLikeNoParams) = x.close  def doCloseEmptyParams(x: CloseableLikeEmptyParams) = x.close()
  trait CloseNoParams { def close: Unit }  trait CloseEmptyParams { def close(): Unit }    def test(na: CloseNoParams, ea: CloseEmptyParams, jc: java.io.Closeable) {      na.close      na.close() // compile error: can't invoke with empty params      doCloseNoArgs(na)      doCloseEmptyArgs(na) // compile error: type mismatch
      ea.close      ea.close()      doCloseNoArgs(ea) // compile error: type mismatch [*]      doCloseEmptyArgs(ea)
      jc.close      jc.close()      doCloseNoArgs(jc) // compile error: type mismatch [*]      doCloseEmptyArgs(jc)  }}

(Here, java.io.Closeable is identical in semantics to the trait CloseEmptyArgs, but is included to show interoperability.)
The incongruity I reported in 4506 is that both cases, a def with no param-list and a def with an empty param-list, can be called without a param list (xx.close), but only defs declared with an empty param-list can be called with it (xx.close()).
However, using structural types, the with/without empty param-list state of a def currently must match exactly, meaning that code intended to work with both CloseNoParams and CloseEmptyParams must have two separate code paths to handle them. No single structural type can match both, even though a single direct calling convention works with both.

I stated in the issue that #2810 was a symptom of this larger problem (in that a library function was originally "def close" and changed to "def close()" to resolve that specific issue).
It feels to me like this situation goes against the grain of the uniform access principle, since defs with or without an empty param-list can be called in the same way -- but structural types don't currently agree. Thoughts?
Todd Vierling
Joined: 2011-04-27,
User offline. Last seen 42 years 45 weeks ago.
Re: Trac #4506: structural types vs. no-arg defs
On Wednesday, April 27, 2011 10:23:44 AM UTC-4, Todd Vierling wrote:
  def doCloseNoParams(x: CloseableLikeNoParams) = x.close  def doCloseEmptyParams(x: CloseableLikeEmptyParams) = x.close()
 
      doCloseNoArgs(na)
      doCloseEmptyArgs(na) // compile error: type mismatch

Bah. In case it wasn't obvious, the original test case used the word "Args", but I changed it, and I didn't fully edit all those instances to say "Params" before posting. All text using "Args" should actually read "Params". :-/
ichoran
Joined: 2009-08-14,
User offline. Last seen 2 years 3 weeks ago.
Re: Trac #4506: structural types vs. no-arg defs
I agree that this is a silly state of affairs, but note that if it is not fixed, you can build your way around it using implicits:

  implicit def noP2withP(c: { def close: Unit }) = new { def close() { c.close } }
  implicit def withP2noP(c: { def close(): Unit }) = new { def close { c.close } }

Add these two lines and now everything will compile.  If you want to only go in one direction, use only one of the implicits.

  --Rex

On Wed, Apr 27, 2011 at 10:23 AM, Todd Vierling <tv@duh.org> wrote:
https://lampsvn.epfl.ch/trac/scala/ticket/4506#comment:2

I'm not sure why the close comment on this issue directed me to http://lampsvn.epfl.ch/trac/scala/changeset/24029, and I'm thinking that perhaps what I was asking wasn't really clear. In any case, here's a code example of the issue, and I've changed it to be more like the case reported in https://lampsvn.epfl.ch/trac/scala/ticket/2810 so that a concrete use case can be understood:

object Test {
  type CloseableLikeNoParams = { def close: Unit }  type CloseableLikeEmptyParams = { def close(): Unit }
  def doCloseNoParams(x: CloseableLikeNoParams) = x.close   def doCloseEmptyParams(x: CloseableLikeEmptyParams) = x.close()
  trait CloseNoParams { def close: Unit }  trait CloseEmptyParams { def close(): Unit }    def test(na: CloseNoParams, ea: CloseEmptyParams, jc: java.io.Closeable) {       na.close      na.close() // compile error: can't invoke with empty params      doCloseNoArgs(na)      doCloseEmptyArgs(na) // compile error: type mismatch
      ea.close      ea.close()      doCloseNoArgs(ea) // compile error: type mismatch [*]      doCloseEmptyArgs(ea)
      jc.close      jc.close()       doCloseNoArgs(jc) // compile error: type mismatch [*]      doCloseEmptyArgs(jc)  }}

(Here, java.io.Closeable is identical in semantics to the trait CloseEmptyArgs, but is included to show interoperability.)
The incongruity I reported in 4506 is that both cases, a def with no param-list and a def with an empty param-list, can be called without a param list (xx.close), but only defs declared with an empty param-list can be called with it (xx.close()).
However, using structural types, the with/without empty param-list state of a def currently must match exactly, meaning that code intended to work with both CloseNoParams and CloseEmptyParams must have two separate code paths to handle them. No single structural type can match both, even though a single direct calling convention works with both.

I stated in the issue that #2810 was a symptom of this larger problem (in that a library function was originally "def close" and changed to "def close()" to resolve that specific issue).
It feels to me like this situation goes against the grain of the uniform access principle, since defs with or without an empty param-list can be called in the same way -- but structural types don't currently agree. Thoughts?

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland