- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Trac #4506: structural types vs. no-arg defs
Wed, 2011-04-27, 15:23
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?
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?
Thu, 2011-04-28, 15:58
#2
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:
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?
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". :-/