Skip to content

Creator application is lost on type alias (e.g. on AnyRef) #10862

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

Closed
rjolly opened this issue Dec 19, 2020 · 10 comments
Closed

Creator application is lost on type alias (e.g. on AnyRef) #10862

rjolly opened this issue Dec 19, 2020 · 10 comments

Comments

@rjolly
Copy link
Contributor

rjolly commented Dec 19, 2020

Minimized code and output

object foo {
  class A(n: Int)
}
type A = foo.A
println(A(1))
        ^
        Not found: A

Expectation : should work as with new

println(new A(1)) // ok
@odersky
Copy link
Contributor

odersky commented Dec 20, 2020

That works as expected since the rules have changed.

@SethTisue
Copy link
Member

at #10784 (comment) you write:

Yes, that's intended. You don't get an apply for a type alias. I think this is what we want. To compare, if I write

type S = scala.collection.immutable.Seq
I still can't do S(1, 2, 3). I'd have to add

val S = scala.collection.immutable.Seq
For the new kind of apply methods, it's the same.

What about the AnyRef case, where you can't AnyRef() anymore. Do we just shrug and say new AnyRef is fine? We can't add val AnyRef = java.lang.Object, since there is no such term.

@rjolly
Copy link
Contributor Author

rjolly commented Dec 20, 2020

It means every time we want to relocate a type, we have to define its constructor proxy by hand. This is eventually not a problem for me.

@SethTisue you can define a AnyRef object:

object AnyRef:
  def apply() = new AnyRef()

println(AnyRef())

@dwijnand
Copy link
Member

Yes, that's intended. You don't get an apply for a type alias. I think this is what we want.

Seeing as you get a pseudo apply for a class, I don't see why you shouldn't also get an apply for an alias to the class. I don't see why whether a type is an alias or the actual class should suddenly destroy the feature. We're back to deciding whether to use apply or new then, while the feature seemed to be intended to make using new the rare exception and apply the norm.

You can't val alias all classes. Starting with Java classes, but also some Scala classes:

scala> object foo { class A(n: Int) }; type A = foo.A; val A = foo.A
1 |object foo { class A(n: Int) }; type A = foo.A; val A = foo.A
  |                                                        ^^^^^
  |                      constructor proxy object A cannot be used as a value

scala> object foo { class A(n: Int); object A }; type A = foo.A; val A = foo.A
// defined object foo
// defined alias type A = foo.A
val A: foo.A.type = foo$A$@6cee903a

scala> A(1)
val res3: foo.A = foo$A@e36bc01

Are users intended to write their own alias-site objects like rjolly's object AnyRef above?

@rjolly
Copy link
Contributor Author

rjolly commented Dec 22, 2020

The cool thing is that you don't actually have to implement apply in he companion:

object foo {
  class A(n: Int)
  object A
}
type A = foo.A
val A = foo.A
println(A(1)) // ok

Edit : for comparison this works, with or without the val statement:

object foo {
  case class A(n: Int)
}
type A = foo.A
val A = foo.A
println(A(1)) // ok

Edit2 : so maybe what we should do is take for granted that MyType in value position always refers to the companion object, without an explicit val. As a matter of fact, this is what import does : make both available at the same time:

object foo {
  class A(n: Int)
  object A
}
import foo.A
println(A(1)) // ok

@odersky
Copy link
Contributor

odersky commented Dec 23, 2020

Yes, as @rjolly writes, we already require val aliases to get e.g. case class apply methods. There's no reason why we should do something different for the other applies.

About AnyRef. I think requiring new AnyRef, or alternatively Object() is fine. I don't think it's a very common use case, outside of tests maybe? We could think about a synthetic val alias for AnyRef, but that would be quite a lot of work to add it. Not sure it's worth that, but if someone wants to look at it and make a PR, I'd be happy to review.

@odersky odersky closed this as completed Dec 23, 2020
@dwijnand
Copy link
Member

I don't have to have an apply defined in order for the creator application Foo() to work (heck I don't even have to have an object Foo). What's the reasoning for that not to be true when Foo is type Foo = Bar (given a class Bar)? As I see it: it's an alias, it's a type being defined - if I can new Foo() it I should be able to Foo() it, IMO. I include case classes in that, btw: if Bar is a case class, IMO a type alias should be enough to allow Bar(). Not any other method of the object, and it should delegate to the apply in the object if it's present (e.g. do hash consing).

@SethTisue
Copy link
Member

SethTisue commented Mar 29, 2021

I don't think it's a very common use case, outside of tests maybe?

when I need a lock to synchronize on, I do:

val lock = new AnyRef
lock.synchronized { ... }

@SethTisue SethTisue closed this as not planned Won't fix, can't repro, duplicate, stale Nov 7, 2024
@SethTisue
Copy link
Member

This came up on Discord today, except instead of AnyRef(), it was NoSuchElementException(), which does not work, even though java.util.NoSuchElementException() does work. The underlying reason is the same.

@SethTisue
Copy link
Member

Might export help us here?

Would the situation be any different if the scala package did export java.util.NoSuchElementException and export java.lang.{Object => AnyRef}, rather than what it does currently?

@SethTisue SethTisue changed the title Creator application is lost on type alias Creator application is lost on type alias (e.g. on AnyRef) Jan 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants