Meanings of underscore (including wildcard imports)

An underscore (_) in pattern stands for (matches) any single character.

So it is absolutely wrong analogy here.

import p.{a => _, _}

It’s just some kind of puzzle, so I can’t see any consistency in scala now.

Underscore is used as a wildcard in almost every functional programming language under the sun. In some, like Idris, you can even use it in expressions, in which case the compiler tries to infer a term for you. This is not unlike import p._, where the compiler tries to infer the right things to import for you.

1 Like

Our usecase for renaming imports is similar, primarily in the context of gRPC-based microservices.

The request/response messages have generated classes with names that match the message names. This means that, if we want to use those same names in our domain classes (which happens more often than not), we need to alias them somehow. When reading code which needs to use both (mostly validation and serialization code), it’s much easier recognize which one you’re looking at if the generated class is aliased with a suffix (Pb, Proto, etc) than it would be if we imported one if it’s containing packages.

It’s not quite an every-day thing, but it’s pretty common.

FWIW, I like the * and as suggestions here, I think they’re much easier to understand at a glance.

(I deleted some other stuff here because I don’t think it adds any value to the discussion.)

2 Likes

Doesn’t it look like an abbreviated pattern match to you?

  a => _

matches name a but renames it _, meaning to ignore it.

  _

matches each thing that is left, and the default is to import it as is, so it’s imported.

If you switch _ to *, since you can’t use * to match “each thing that’s left” in any other context, you get less regular, not more.

1 Like

No it does not.

I usually use
‘’’
val a = _ // scala
_ = fun() // swift
‘’’
So I associate it with “ignore”.

import p.{a => ignore, ignore}

What???
Such association force me to go to documentation.

I don’t think regularly is a golden rule. if it leads to low cohesion and high coupling it will be worse.

At least
import n.{* except a }
Doesn’t puzzle me at all.

Try to rename something too.

1 Like

import n.* except a
import n.a as b

; )

IMHO: Rare construction should be more intuitive than more succinct.

1 Like

I always use short package name aliases in this kind of situation. There is no need to define aliases for each class separately.

Even if I like the new syntax proposal and I (as a univ. teacher using Scala as beginner language) can live with all three options, I think @lihaoyi 's arguments are pretty strong (esp. (1) better draw a line and get it out rather than delaying and (2) this is not a big issue in practice in industry), so I think I should vote for “Do nothing” in 3.0 (and perhaps take this improvement later in 3.x or even 4.x).

To me it boils down to what we believe increases the probability most of Scala3 being loved by Scala2-practitioners AND people coming from other languages directly to Scala3. In I think Scala2-practitioners might have enough with all current changes in Scala3 already…

An argument against my above reasoning would be if we prioritize newcomers to Scala that go directly to Scala3, who might be the biggest community boost in the long run (?). Then the arguably cleaner syntax might be the best choice and hence option 1 above. So it’s a delicate trade-off between disturbing short-term migration and long-term on-boarding of newcomers.

1 Like

I think this “who might be the biggest community boost” is a fallacious line of thought. If you ignore the needs of the current user base (too much) in favour of newcomers, you risk alienating the very people who are instrumental in bringing the lion’s share of those newcomers into the language. That means you risk tanking the language completely or ending up in a Python 2/3 situation that takes years and years and years to resolve.

As a small appetizer of this point, spark still hasn’t been able to fully upgrade to scala 2.13, more than 1.5 years after its release, and we’ll likely reach 2 years between the release of 2.13 and a 2.13-compatible spark version.

3 Likes

Yes, that is a dreadful risk. I agree that the existing user base is super-important for on-borading the future user base. I’m not, in this case of importing with * vs _ etc, sure about how much it really matters, in the light of all other changes though.

1 Like

No idea, other than potentially inching us closer to the threshold for, “I don’t have the time or energy to deal with this.” Unfortunately, that’s also at a bit of a low ebb because of the pandemic, and worse there’s no real way to determine where that line is with any degree of accuracy.

Anecdotally, I’ve seen at least one reference (I think on Reddit, it’s been a couple of days) to the difference between Scala 2 & 3 couched in terms of Perl & Raku instead of Python 2 & 3. I haven’t seen that before, and while hopefully it’s a one-off comparison, I find it worrying that a reference to Scala 3 as a completely different language was treated as a reasonable thing - and worse, that I could kind of see where they were coming from. That’s probably an indication that we’re at least approaching the level of changes where things become overwhelming.

2 Likes

Just yesterday, a software engineer at my organization made a presentation extolling the benefits if we upgrade all Scala projects to version 2.13.

2 Likes

As one of the main book authors (Programming Scala from O’Reilly), who’s finishing a Scala 3 update, here are my thoughts on the proposed changes to the import syntax:

  1. I care most about converging quickly on the final syntax, whatever it is, and the migration plan over different releases, so I can update the book, which is basically finished. I don’t see this as a big effort…
  2. I don’t want to delay the release of Scala 3 any more, even if it means skipping some late-breaking good ideas.
  3. Like braceless syntax, it will make many existing Scala users mad at first, but they might grow to like it after using it.
  4. On balance, I like going back to *. I was thinking the other day that _ looks a bit odd, now that we’re eliminating some other uses of it.
  5. On the other hand, if import foo.{bar => _} doesn’t go away (unless I missed something in this long thread), then keeping _ is more consistent.
  6. Unless I’m mistaken, we removed all (temporary) uses of “as” recently, so using it for imports feels like an ad hoc special case and hence not really that much better than =>. If “as” were still used elsewhere, I would like this change more.
  7. It’s nice to be able to drop {} when you rename one thing, but I assume you’ll still need {} for more than one, such as import foo.bar.{A as A2, B as B2}. I suppose the exception that {} can be omitted for one rename is analogous to omitting {} for one-expression methods, but special cases vs. rigid consistency means learning one more way to do something. I’m not sure it’s worth it.
  8. For people who work in IDEs, how often do they actually read and write import statements when the IDE can manage them semi-automatically? Maybe the improvement just isn’t that important to most people.
  9. I have a lot of content in the book already about how features will migrate over the next few releases. It can feel a bit overwhelming. (I use -source 3.1 in the examples sbt build, to emphasize “the future”.)

On balance, I’m not convinced these changes are worth making, but if they go forward, just do it quickly.

14 Likes

I also want to point out: Scala’s syntax was in no way frozen across the 2.x line (from 2006 to now), and yet BooksAndMoocs didn’t seem to suffer for it.

It’s all but guaranteed that within 12 months, there will be widely agreed-upon changes to the syntax waiting to be released. Should we save those improvements for another 5-8 years, to 4.0, so that BooksAndMoocs can once again be asked to please refresh themselves? If the primary holdup to improving the language is BooksAndMoocs, is that a problematic coupling? I’d argue it’s the BooksAndMoocs’ responsibility to keep up with the language, rather than the language’s responsibility to stay consistent with the BooksAndMoocs.

6 Likes

So we dropped the as once and then try to reintroduce it again?
I think we can change import p._ to import p.*.
Kotlin is using as https://kotlinlang.org/docs/reference/grammar.html#importHeader for import alias,
and also for type casting https://kotlinlang.org/docs/reference/keyword-reference.html
If we add as ,then I expect it to be used in more places then we can drop asInstanceOf method

That reminds me of OpenGL saga, when people try to learn OpenGL, you get so much mixed and outdated information from OpenGL 2, OpenGL 3 completely changed most of the stuff but was still backwards compatible, But searching up-to-date information/tutorials was confusing.

OpenGL 5 would be a disaster, until they just decided to just rename to Vulkan and start clean slate.

If we’re moving from symbols to keywords how about:

import prefix.{a as b}
import prefix.{_ except c}

Is there ever import exclusion without wildcard? If not then maybe just

import prefix.!c

More possibilities:

import prefix.{* - c}
import prefix.{_ - c}

If we have to pick a new syntax I think I like the last one the best, followed by ‘except’

(I still think too many changes in one release a.k.a. waterfall in software is never a good idea.)