Import Philosophy

package helloworld;
 
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
 
public class HelloWorld extends Application {
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Hello World!");
        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction(new EventHandler<ActionEvent>() {
 
            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });
        
        StackPane root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }
}

I have a general concern that Scala 3 might become too opinionated. One of the great strengths of Scala 2, was that it allowed developers to programme according to their own philosophies. That it allowed programmers / companies / organisations of differing opinions to write code to their own styles and methodologies.

So I understand that many people like to use precisely targeted imports as in this example. I know this is from Java but the same principles still apply. But I would like to be able to craft APIs, where the library user can not only write the Hello World app of the domain / library framework, with a single import, but can also create the common use cases with a single import.

The import boilerplate / time consumption has considerably increased since I started programming Scala. First with the removal of automatic import inheritance from a package’s parent packages. So every package name component must be put as a separate import.

More recently with warnings for unused imports. When I’m developing I’m constantly commenting and uncommenting lines of code. But that means I constantly have to go back and forward to the top of the file to comment and uncomment the imports. Imagine if println and immutable.List required explicit imports. Well the same principle applies to a library / programming domain. I want all the commonly used classes traits methods etc, just to be there ready to use without requiring a an explicit import.

Again this comes back to differing programming strategies / styles/ philosophies. So for example if I were designing the API, I wouldn’t have three traits / classes all called Set. I would probably go for Set, MutSet and GenSet, the immutable.Set getting the short name as its the commonly used name. So differing naming strategies produce different needs in terms of import conventions.

IMHO if Signficant-whitespace is obligatory it will be great blow to different styles and methodologies.

I can sugest that scala 3 offers:

so, you can write something like(it is not tested):

object Context {
    export scanUnit._
    export printUnit._
  }

class someClass{
   import Context._
}

Nevertheless, I think, scope management is not the strongest side of scala 2 and scala 3.

1 Like

It’s hard to imagine an API more heavily used by the Scala community than the Emoji project.

But what a hassle to import everything you need just to get started!

Here is a sample predef for use with -Yimports:java.lang,scala,scala.Predef,emojion.Premoji.

I’m sure it will look better with whatever export facility they cook up for Scala 3. This is merely what you can do today with that old rust bucket, Scala 2.

~/projects/emojion$ cat src/main/scala/Premoji.scala

package emojion

import scala.language.implicitConversions

object Premoji {
  type Emoji = com.lightbend.emoji.Emoji
  val  Emoji = com.lightbend.emoji.Emoji
  type ShortCodes = com.lightbend.emoji.ShortCodes
  val  ShortCodes = com.lightbend.emoji.ShortCodes

  implicit val defaultShortCodes: ShortCodes = ShortCodes.Defaults.defaultImplicit

  import com.lightbend.emoji.ShortCodes.Implicits.Emojilator

  implicit def emojilator(sc: StringContext): Emojilator = Emojilator(sc)
}