Why is it illegal to put package-level defs/types/implicits at the root-level of a file? - scala

This question has been bugging me ever since I started using Scala. So here's my trail of thought:
Scala doesn't have the requirement, which Java has, that everything has to be in a class—this is a good thing!
Scala has functions, i.e. methods without a class/object
packages are objects, so if you define a class in a package, it'll go into the package object
some things have to be put into package objects explicitly, whereas some things don't—WHY?
I think it's just ugly to have to write:
package foo.bar
object `package` {
type Foo = Bar
def fact(n: Int): Int = ???
}
instead of just
package foo.bar
type Foo = Bar
def fact(n: Int): Int = ???
So: does anybody know when/why was it decided that it's better to require explicit wrapping with (the otherwise implicit) package objects? I'm constantly finding myself annoyed with the extra level of indent and boilerplate introduced by the obscure object package declaration, which is annoying just for the same reason this is annoying in Java:
class MyMath {
public static int fact(int n) { ... }
}

Related

Why this class need to be abstract in scala?

In java and c#,I can write this:
class Tree {
Tree left;
Tree right;
}
but in scala:
class Tree{
val left:Tree
val right:Tree
}
I need to add abstract for class,or write:
val left:Tree=new Tree()
I can write this:
trait Tree{
val left:Tree
val right:Tree
}
but why if I use class,I "have to"and abstract?I don't think it's a good design
Thanks!
The reason you can write
class Tree {
Tree left;
Tree right;
}
in Java and C# is because the fields are initialized to null by default (or to 0, etc. depending on the type). Scala's designers decided this is a bad idea and you need to initialize them. So the approximate Scala equivalent is
class Tree {
// note, not val
var left: Tree = null
var right: Tree = null
}
which is legal (but probably not something you actually want to use).
but why if I use class,I "have to"and abstract?
You have to mark your class with the abstract keyword because your class is abstract. It cannot possibly be instantiated.
I don't think it's a good design
Good design is subjective. The designers of Scala thought that being explicit in this case, rather than making the class automatically abstract was good design. I would guess that the majority of the Scala community agrees with them.
You disagree, and that is perfectly okay.
It happened because scala sometimes considers val and def as method like declarations. Let me elaborate, please, for instance, we have the next Scala example:
class Example {
val a: String = "example"
}
val example = new Example()
println(example.a)
You may see that a declared as a field. Unlike Java, we can change this declaration easily to def and everything remains compiling:
class Example {
def a: String = "example"
}
val example = new Example()
println(example.a)
In the case of Java (not sure about C# I've never worked with it), if you would like to access the field over getter method, you will need to change all invocation places from field to method access.
Now, you can consider val as let's say sort of eager cached def version - if so then declaring val without actually value assignment implicitly considered by compiler as declaring method without implementation and that's why compiler says Tree is an abstract class - because left and right has no values, hence they are abstract. In order to make it non-abstract, you need to assign a value to fields or use var if you would like to proceed with mutable structure, e.g.:
class Example {
val a: String = "example"
}
val example = new Example()
println(example.a)
Scatie: https://scastie.scala-lang.org/bQIcVNk9SN6qJhbL32SMUQ

scala scoping brings in types not shown in import

I read an article concerning that scala's type inference might have done too
much:
Given this piece of code:
package A1 {
case class Foo(a: Int)
package object A2 {
def bar() = Foo(1)
}
}
--
import A1.A2._
object Main extends App {
val a: Foo = bar() // error: not found type Foo
}
It won't compile as Main can't see Foo unless we also import A1.Foo.
Whereas if the type annotation is taken away, then it fine:
import A1.A2._
object Main extends App {
val a = bar()
}
The author thinks this comparing to java, where we have to explicitly import whatever types we're using, would reduce readability as imports no long have complete information about the set of types we're using.
I think what he wants is that the types being used, explicitly or implicitly, need to be imported to make it clear what the code depends on and perhaps to assist some static analysis tools.
For this problem I wonder what you think about it.
EDIT:
As #flavian pointing out, this has little to do with type inference, more of how scoping works.
EDIT2:
I have a second thought on this. Maybe this question is not important if an IDE can automatically add imports(even for those used implicitly) if the developer wants to.
--
In your first example the compiler sees
val a: Foo = bar()
and doesn't know what Foo is, so it complains.
To fix this code there are three options.
// import Foo
import A1.Foo
val a: Foo = bar()
// use the fully qualified name
val a: A1.Foo = bar()
// let the compiler infer the type
val a = bar()
These all compile the same.
The last option is not avaliable to Java.
The author thinks this comparing to java, where we have to explicitly import whatever types we're using
Not true.
// we can use Foo with no import
useFoo(x.getFoo());
// and we can use fully qualified names
A1.Foo foo = bar();
The compiler will add to the compiled class file a list of all classes that are needed by the class.
I don't think type inference is the question at play in here. Members propagate in scope through direct import or inheritance. If you had:
trait A1 {
case class Foo(..)
}
object A2 extends A1
This would correctly import Foo into scope. Again, as far as I know this is not a type inference problem, but rather with the fact that imports and implicits propagate only through inheritance. It's more about how scoping works in Scala than anything else.

Scala pass-through wrappers

Very many times, I'll want to "replace" a single method of a given object.
foo: Foo
foo.bar(i) // original
foo.baz(s) // replace this implementation
I'll wind up creating a pass-through wrapper class.
class FooWrapper(foo: Foo) extends Foo {
def bar(i: Int) = foo.bar(i)
def baz(s: String) = foo.baz(s)
}
And then
foo: Foo
val foo2 = new FooWrapper(foo) { def baz(s: String) = ... }
foo2.bar(i)
foo2.baz(s)
This works with traits and classes, and works without modifying the source code of the type.
I use this quite a bit, particularly when adapting libraries or other bits of code.
This can get tedious with lots of methods. The other day, I wanted to replace the shutdown method on an ExecutorService instance, and I had to do this for a dozen methods.
Is this a common idiom, or is this normally done another way? I suspect this could be done nicely with a macro, though I haven't found any existing ones that do this.
You can achieve that with AOP (Aspect-oriented programming)
There're many libraries to do so, try this one -
https://github.com/adamw/scala-macro-aop
Note that this library is in POC stage for now so you might look for something more mature. I've put it here because I think it shows the concept very clearly.
For your example you'll have to do something like
class FooWrapper(#delegate wrapped: Foo) extends Foo {
def baz(i: Int) = ???
}

Can I define and use functions outside classes and objects in Scala?

I begin to learn Scala and I'm interesting can I define and use function without any class or object in Scala as in Haskell where there is no OOP concept. I'm interested can I use Scala totally without any OOP concept?
P.S. I use IntelliJ plugin for Scala
Well, you cannot do that really, but you can get very close to that by using package objects:
src/main/scala/yourpackage/package.scala:
package object yourpackage {
def function(x: Int) = x*x
}
src/main/scala/yourpackage/Other.scala:
package yourpackage
object Other {
def main(args: Array[String]) {
println(function(10)); // Prints 100
}
}
Note how function is used in Other object - without any qualifiers. Here function belongs to a package, not to some specific object/class.
As the other answers have indicated, its not possible to define a function without an object or class, because in Scala, functions are objects and (for example) Function1 is a class.
However, it is possible to define a function without an enclosing class or object. You do this by making the function itself the object.
src/main/scala/foo/bar/square.scala:
package foo.bar
object square extends (Int => Int) {
def apply(x: Int): Int = x * x
}
extends (Int => Int) is here just syntactic sugar for extends Function1[Int, Int].
This can then be imported and used like so:
src/main/scala/somepackage/App.scala:
package foo.bar.somepackage
import foo.bar.square
object App {
def main(args: Array[String]): Unit = {
println(square(2)) // prints "4"
}
}
No, functions as "first-class objects" means they are still objects.
However, it is still easy to construct a Scala application that does nothing but invoke a function that is arbitrarily composed.
One Odersky meme is that Scala's fusion of FP and OOP exploits modularity of OOP. It's a truism that Scala doesn't strive for "pure FP"; but OOP has real consequences for everyday programming, such as that a Map is a Function, as is a Set or a String (by virtue of enrichment to StringOps).
So, although it's possible to write a program that just invokes a function and is not structured OOPly, the language does not support active avoidance of OOP in the sense of exposure to inheritance and other unFP things like mutable state and side effects.

How can I add new methods to a library object?

I've got a class from a library (specifically, com.twitter.finagle.mdns.MDNSResolver). I'd like to extend the class (I want it to return a Future[Set], rather than a Try[Group]).
I know, of course, that I could sub-class it and add my method there. However, I'm trying to learn Scala as I go, and this seems like an opportunity to try something new.
The reason I think this might be possible is the behavior of JavaConverters. The following code:
class Test {
var lst:Buffer[Nothing] = (new java.util.ArrayList()).asScala
}
does not compile, because there is no asScala method on Java's ArrayList. But if I import some new definitions:
class Test {
import collection.JavaConverters._
var lst:Buffer[Nothing] = (new java.util.ArrayList()).asScala
}
then suddenly there is an asScala method. So that looks like the ArrayList class is being extended transparently.
Am I understanding the behavior of JavaConverters correctly? Can I (and should I) duplicate that methodology?
Scala supports something called implicit conversions. Look at the following:
val x: Int = 1
val y: String = x
The second assignment does not work, because String is expected, but Int is found. However, if you add the following into scope (just into scope, can come from anywhere), it works:
implicit def int2String(x: Int): String = "asdf"
Note that the name of the method does not matter.
So what usually is done, is called the pimp-my-library-pattern:
class BetterFoo(x: Foo) {
def coolMethod() = { ... }
}
implicit def foo2Better(x: Foo) = new BetterFoo(x)
That allows you to call coolMethod on Foo. This is used so often, that since Scala 2.10, you can write:
implicit class BetterFoo(x: Foo) {
def coolMethod() = { ... }
}
which does the same thing but is obviously shorter and nicer.
So you can do:
implicit class MyMDNSResolver(x: com.twitter.finagle.mdns.MDNSResolver) = {
def awesomeMethod = { ... }
}
And you'll be able to call awesomeMethod on any MDNSResolver, if MyMDNSResolver is in scope.
This is achieved using implicit conversions; this feature allows you to automatically convert one type to another when a method that's not recognised is called.
The pattern you're describing in particular is referred to as "enrich my library", after an article Martin Odersky wrote in 2006. It's still an okay introduction to what you want to do: http://www.artima.com/weblogs/viewpost.jsp?thread=179766
The way to do this is with an implicit conversion. These can be used to define views, and their use to enrich an existing library is called "pimp my library".
I'm not sure if you need to write a conversion from Try[Group] to Future[Set], or you can write one from Try to Future and another from Group to Set, and have them compose.