Proposal: Simplifying the Scala getting started experience

Minimal SBT project:

Give it a name, for example “smurf”

Create folder smurf as project root folder.

In root folder, create file src/main/scala/smurf/app/Smurf.scala with content:

= = = = = = =

package smurf.app

object Smurf {
def main(args: Array[String]): Unit = {
println(“Let’s smurf!”)
}
}

= = = = = = =

Back in the root folder smurf, type

sbt run

Watch it print:

Let’s smurf!

Oliver’s recipe also works if you put Smurf.scala at the root level, without bothering to nest it all the way down inside src/main/scala/smurf/app:

% mkdir demo
% cd demo
% echo 'object Smurf extends App { println("hello world") }' > Smurf.scala
% sbt run
[warn] No sbt.version set in project/build.properties, base directory: /Users/tisue/tmp/demo
[info] Set current project to demo (in build file:/Users/tisue/tmp/demo/)
[info] Updating ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/tisue/tmp/demo/target/scala-2.12/classes ...
[info] Done compiling.
[info] Packaging /Users/tisue/tmp/demo/target/scala-2.12/demo_2.12-0.1.0-SNAPSHOT.jar ...
[info] Done packaging.
[info] Running Smurf 
hello world
[success] Total time: 3 s, completed Mar 27, 2019 6:11:29 PM
% 

-warn cuts down on the noise level:

% sbt -warn run
hello world
1 Like

To say the truth I do not think it is simple.
Here would be simple :wink:

But I think it does not matter.
In real life we spend about half a day to set up our workstations in new os. The real simplicity in such complicated stack(java, sbt, bloop, ide) can be achieved only by thin client(web browser, ssh terminal) and cloud server wich is alredy deployed somewhere.

Here’s the minimal Python project:

In smurf.py write

print("Let's smurf!")

and type python smurf.py.


Here’s the minimal R project:

In smurf.r write

cat("Let's smurf!\n")

and run Rscript smurf.r


Minimal Julia project:

Create a file smurf.jl containing

println("Let's smurf!")

and run julia smurf.jl


Minimal Rust project

Pick a name, like smurf. Type cargo new smurf.

Enter the smurf directory.

Inside src/main.rs change the line

    println!("Hello, world!")

to

    println!("Let's smurf!")

Run with cargo -q run (for a quiet run).


Minimal sbt doesn’t look so great in comparison; half of that is sbt’s fault and half is Scala. We should fix both.

3 Likes

You can write in Smurf.sc:

println(“Let’s smurf!”)

and then run it with

amm Smurf.sc

where amm is the executable of Ammonite.

No, Scala with SBT is not quite as simple, but I think it is pretty good considering that it is optimized for larger projects. Like, projects where you have five or more library dependencies, where you have tests, where your project might itself be used as a library dependency by some other projects and you want to publish it to an artifact repository, and perhaps you build a web service, or use an external database, etc.

Scala is supposed to mean “Scalable Language”. I’m assuming that means scaling up, not down, right?

If you want to use Scala as if it was Python, don’t make the language more complicated, use a specialized tool instead, like Ammonite.

You may hate the application object and the main method, but whatever you choose, on the JVM it will be an object and a main method, and they will be visible on various occasions, so trying to pretend they don’t exist just adds a layer of obfuscation.

Except that’s not official, and very well could go away if Li Haoyi stops paying attention (depending on whether anyone wants to pick it up to keep it going as the Scala compiler evolves). And it’s awkward to bridge that way and the build-tool way to do things.

Thus this proposal: this, or something much like it, should be standard.

Sometimes obfuscation in service of simplicity is a good thing.

The same logic argues for doing away with case classes (magic methods that you pretend don’t exist), objects (more magic), for-comprehensions (entirely magic), old-style closures (yet more magic), and so on.

Pretending that something doesn’t exist is very handy when it doesn’t matter.

Except nothing prevents it from handling small projects better save history and inattention. So…yes…it’s pretty good at what it does, but that doesn’t really argue whether or not it should do something else better. (Well, one could also argue: in a big project we don’t want new users involved because they’ll likely muck stuff up, so the tooling should be formidable enough to scare most of them away until they’ve learned enough to be helpful rather than a danger. But I don’t think that’s what you were intending to argue?)

So I’m not sure how the point is relevant to this thread which is specifically proposing ways to simplify the Scala getting started experience.

2 Likes

Why do you think it is possible at all?
I think dynamic type languages always will be able to be more simple than static type languages. (if one is not java script :)) )

It is always script in practice.
But as you have said.

Why do we have such situation?
I think static type languages does not suite well for small programs.

If I were linux administrator I would be quite scared the need to recompile all scripts just for of one bug fix in some core script :))

So I just can not see any real motivation for propagation tools like “Ammonite”

I like “ammonite” but I think without “dynamic invocation” it always be something around scala users.

So I just cannot see which power can make scala practical usage more simple than Intellij idea can :wink:

Why not? Seriously: in a language with reasonably good type inference, I don’t see any good reason why it should be any worse for this purpose than any other language. And Ammonite serves as a pretty good proof of concept…

4 Likes

I think it is possible because we already have something that does it, namely Ammonite!

I just showed a roughly equivalent example in Python and Scala. If you nonetheless prefer to use Python or whatever, that’s fine! But don’t derail the conversation of people who know how to and do use Scala for the same things, to good effect, and would like to make it more inviting for others.

2 Likes

Having done non-trivial automation with bash, I can tell you that recompilation is much better than having it fail at runtime because of a typo in an uncommon execution path.

I’m not as familiar with Ammonite as it sounds like I should be. Having it blessed would go a long way towards making it easier to defend using it to replace those scripts that have progressed into the awkward territory of having grown beyond bash and not yet to the point of justifying a rewrite in Scala+SBT.

3 Likes

Yes It is really good.

Seriously It is very painful question.
I remember we have discussed what to use for dynamic expression instead of plsql. And of course the first thing we have tried is tools.reflect.ToolBox
It have been a very big disappointment. In comparition to nashorn(javascript)

  • the performance is awful (I do not remember it is 10-100 times slower)
  • the memory usage is terrible

We have currently so much troubles with hot updates and binary compatibility which just doesn’t exist in dynamic type languages.

So I just do not believe in scala scripting in general.

It is very good until you do have binary incompatibility hell.
If you write something local it is not problem, but in general it can be hell. Why do you think bash\javascript\lua has dynamic type system :wink:

Sorry, if you would like to compare python and Ammonite I wish you good luck.
I hope that someday Ammonite will be more popular in scripting.

This is an advanced use case. It’s not relevant to the getting started / non-language-expert scenario we’re talking about here.

It is true that interpreted languages tend to be able to evaluate expressions (once) very fast, faster than a compile-execute cycle. But for the scenarios we’re talking about nobody cares about that level of overhead; it’s swamped by the time to type your few-line script.

This is also an advanced use case, and thus also not relevant. (It’s also wrong-in-spirit because you exchange avoidable (if you recompile instead of just relinking) bincompat problems with unavoidable runtime crashes, but there can be cases where bincompat fails but source compatibility is okay and maybe you have a lot of these. Anyway, it doesn’t matter how accurate the observation is because it’s not the use case we’re thinking about.)

Sorry I have understood that that you are not talking about it from your previous message.
I just do not want to continue discussion with such argumentation quality.

You think that it does not matter.
Ok, it is clear.

Excuse me for my question.

All this talk of simplifying things is great. But I think the formula is Effort = Complexity X DiscoveryEffort, meaning to say, if something takes 1 step but you have to dig through 5 cryptic pages of documentation to figure out what that step is, you might be worse off than with something that takes 10 steps, each of which is governed by multiple absurd rules, but there is a single page, at hand when you need it, written in very readable English, that walks you through exactly what to do. (Obviously both are exaggerated nightmare scenarios, I’m just trying to explain what I mean by those two variables.) So again, not to minimize any of this, especially since simplifying things also reduces the amount of documentation needed… but let’s not forget that another important factor is how easy to find and easy to read the documentation is.

1 Like

It is good to think about effort. But there is another very important question.
It is profit. So we have motivation = profit / Effort
Ok, I have done it and what is it next?
For example it is very easy to open scala online and write “hello word”.
But there are no real profit in everyday life because it do not solve everyday tasks.

So I think there are no sence to do very simple examples which have no practical proffit.

So making simple sbt project is relatively hard. But this can help you to start real project at least if you really need it.

Except real people mostly don’t behave like this. They go for a whole series of least-resistance steps. If they can’t find the documentation, or if it doesn’t work the first or second time, or if they have to type boilerplate, or if they don’t get an instant pat on the back, they walk away and don’t do it at all or do it in python or js.

The point of making println("Hi Mum") zero boilerplate isn’t that it has utility. It’s that it gives users an instant reward. They have got the computer to do something.

1 Like

Except real people mostly don’t behave like this.

IMHO
May be you are right.

But for me a language is like a tool. if I have a task I will take appropriate tool whether it is pliers or a screwdriver it depends on a task.
I just have noticed that it may be impossible to make a good\simple hammer from pliers.

If you really enjoy such things ok, just do it.
But I think
if a pro does such things it can be very beautiful. But when you teach such things students it can be the way to really big dissapointments.
I have seen many such disappointments.
I do not think such simplicity is very good, but if somebody like it it is not my deal after all.

What I really dream about it is a mode which allow to write right scripts in scala.

  • When you just do not need a build system at all
  • where there are no binary incompatibility problem.
  • When a single error in some unimportant file do not stop compilation at all.
  • when you can simply call a method to usual scala code

It is a real key to simplicity :wink: (when all you need is vi editor and installed package)

it would be cool if there were a real simple scripts. There were a real big communities on such tasks and so on.

1 Like

A language is easy to learn if it is governed by simple rules.

For example, “All code resides in methods, and all methods are part of an object” is a simple rule.

If you enable one-line apps but complicate the rules, you are not helping beginners.