I'm just starting to learn Scala. While browsing through the Scaladocs I saw this method definition in mutable.Map:
def -=(elem1: A, elem2: A, elems: A*): Map.this.type
Removes two or more elements from this shrinkable collection.
elem1 the first element to remove.
elem2 the second element to remove.
elems the remaining elements to remove.
returns the shrinkable collection itself
Why would you need to define elem1 and elem2 explicitly if you're just going to define elems with a * anyway?
Notice that there is already a separate overloaded method with a single parameter:
abstract def -=(key: A): Map.this.type
So the two more more parameters constraint is to avoid ambiguous calls. The reason for a separate method with a single parameter may be efficiency. Note that calling a variable argument method involves creating an array in the background, which would be wasted if there is only a single element to remove.
As the single-argument version of the method is abstract while the multiple-argument version is concrete, I would not be surprised if the implementation of the latter actually called the former in (a functional equivalent of) a loop. (Update: a quick code check verified my guess, although the call is indirect via --= .)
I would say because of the two or more condition.
With that signature, you clearly enforce at least two arguments of type A to be passed to the method.
If you used only *elems, it would mean removing 0 or more elements, which wouldn't make much sense.
The fact that you specifically have a signature for removing 2 or more, and whether it makes sense or not, is beyond the scope of this answer. Like #Péter Török said, the reason for overloading this method with one param, and two or more params may be efficiency.
Related
I am nearly completely new to Scala, a few months on. I noticed some wild signatures. I have worked through generics with contrapositive/copositive/extensions/invariance, and most of the basics. However, I continue to find some of the method signatures a bit confusing. While I find examples and know what the signatures produce, I am still a bit at a loss as to some of the functionality. Googling my questions has left me with no answers. I do have the general idea that people like to beat the basic CS 1 stuff to death. I have even tried to find answers on the scala website. Perhaps I am phrasing things like "expanded method signature" and "defining function use in scala signature" wrong. Can anyone explain this signature?
futureUsing[I <: Closeable, R](resource: I)(f: I => Future[R])(implicit ec: ExecutionContext):Future[R]
My guess is that after the initial generics and parameter declaration with a parameter of type I, the body is defined and the final portion is any objects specific to the function or that must be looked up in an implicit scope (are they destroyed afterwards?). Can anyone layout an expanded method signature so I know what code I am using? Is there a particular order the last two parts must be in?
Note
After a bunch more searching, I found a few valid responses I can throw together:
-Scala - Currying and default arguments
-why in Scala a function type needs to be passed in separate group of arguments into a function
There is no set ordering just that implicits must be last. Placement is about dependency which flows left to right as someone down the list in one of the above answers pointed out. Why I cannot have implicits first and everything depending on them afterwards is odd since having nothing available causes an error and things will likely depend on a given implicit.
However, I am still a bit confused. When specifying f: I => Future[R], and needing to supply the last argument, lets pretend it would be any implicit, would I need to do something more like:
futureUsing(resourceOfI)({stuff => doStuff(stuff)})(myImplicit)
Is this even correct?
Could I do:
futureUsing(resourceOfI)(myImplicit)({stuff => doStuff(stuff)})
Why? I am really trying to get at the underlying reasons rather than just a binary yes or no.
Final Note
I just found this answer. It appears the order cannot be changed. Please correct me if I am wrong.
Scala: Preference among overloaded methods with implicits, currying and defaults
Can anyone explain this signature?
futureUsing[I <: Closeable, R]
futureUsing works with two separate types (two type parameters). We don't know exactly what types they are, but we'll call one I (input), which is a (or derived from) Closable, and the other R (result).
(resourse: I)
The 1st curried argument to futureUsing is of type I. We'll call it resourse.
(f: I => Future[R])
The 2nd curried argument, f, is a function that takes an argument of type I and returns a Future that will (eventually) contain something of type R.
(implicit ec: ExecutionContext)
The 3rd curried argument, ec, is of type ExecutionContext. This argument is implicit, meaning if it isn't supplied when futureUsing is invoked, the compiler will look for an ExecutionContext in scope that has been declared implicit and it will pull that in as the 3rd argument.
:Future[R]
futureUsing returns a Future that contains the result of type R.
Is there a specific ordering to this?
Implicit parameters are required to be the last (right most) parameters. Other than that, no, resourse and f could have been declared in either order. When invoked, of course, the order of arguments must match the order as declared in the definition.
Do I need ... implicits to drag in?
In the case of ExecutionContext let the compiler use what's available from import scala.concurrent.ExecutionContext. Only on rare occasions would you need something different.
...how would Scala use the 2nd curried argument...
In the body of futureUsing I would expect to see f(resourse). f takes an argument of type I. resourse is of type I. f returns Future[R] and so does futureUsing so the line f(resourse) might be the last statement in the body of futureUsing.
It was quite a surprise for me that (line <- lines) is so devastating! It completely unwinds lines iterator. So running the following snippet will make size = 0 :
val lines = Source.fromFile(args(0)).getLines()
var cnt = 0
for (line <- lines) {
cnt = readLines(line, cnt)
}
val size = lines.size
Is it a normal Scala practice to have well-hidden side-effects like this?
Source.getLines() returns an iterator. For every iterator, if you invoke a bulk operation such as foreach above, or map, take, toList, etc., then the iterator is no longer in a usable state.
That is the contract for Iterators and, more generally, classes that inherit TraversableOnce.
It is of particular importance to note that, unless stated otherwise, one should never use an iterator after calling a method on it. The two most important exceptions are also the sole abstract methods: next and hasNext.
This is not the case for classes that inherit Traversable -- for those you can invoke the bulk traversal operations as many times as you want.
Source.getLines() returns an Iterator, and walking through an Iterator will mutate it. This is made quite clear in the Scala documentation
An iterator is mutable: most operations on it change its state. While it is often used to iterate through the elements of a collection, it can also be used without being backed by any collection (see constructors on the companion object).
It is of particular importance to note that, unless stated otherwise, one should never use an iterator after calling a method on it. The two most important exceptions are also the sole abstract methods: next and hasNext.
Using for notation is just syntactic sugar for calling map, flatMap and foreach methods on the Iterator, which again have quite clear documentation stating not to use the iterator:
Reuse: After calling this method, one should discard the iterator it was called on, and use only the iterator that was returned. Using the old iterator is undefined, subject to change, and may result in changes to the new iterator as well.
Scala generally aims to be a 'pragmatic' language - mutation and side effects are allowed for performance and inter-operability reasons, although not encouraged. To call it 'well-hidden' is, however, something of a stretch.
I have realized that my typical way of passing Scala collections around could use some improvement.
def doSomethingCool(theFoos: List[Foo]) = { /* insert cool stuff here */ }
// if I happen to have a List
doSomethingCool(theFoos)
// but elsewhere I may have a Vector, Set, Option, ...
doSomethingCool(theFoos.toList)
I tend to write my library functions to take a List as the parameter type, but I'm certain that there's something more general I can put there to avoid all the occasional .toList calls I have in the application code. This is especially annoying since my doSomethingCool function typically only needs to call map, flatMap and filter, which are defined on all the collection types.
What are my options for that 'something more general'?
Here are more general traits, each of which extends the previous one:
GenTraversableOnce
GenTraversable
GenIterable
GenSeq
The traits above do not specify whether the collection is sequential or parallel. If your code requires that things be executed sequentially (typically, if your code has side effects of any kind), they are too general for it.
The following traits mandate sequential execution:
TraversableOnce
Traversable
Iterable
Seq
LinearSeq
The first one, TraversableOnce only allows you to call one method on the collection. After that, the collection has been "used". In exchange, it is general enough to accept iterators as well as collections.
Traversable is a pretty general collection that has most methods. There are some things it cannot do, however, in which case you need to go to Iterable.
All Iterable implement the iterator method, which allows you to get an Iterator for that collection. This gives it the capability for a few methods not present in Traversable.
A Seq[A] implements the function Int => A, which means you can access any element by its index. This is not guaranteed to be efficient, but it is a guarantee that each element has an index, and that you can make assertions about what that index is going to be. Contrast this with Map and Set, where you cannot tell what the index of an element is.
A LinearSeq is a Seq that provides fast head, tail, isEmpty and prepend. This is as close as you can get to a List without actually using a List explicitly.
Alternatively, you could have an IndexedSeq, which has fast indexed access (something List does not provide).
See also this question and this FAQ based on it.
The most obvious one is to use Traversable as the most general trait which will have the goodies you want. However, I think you are generally better sticking to:
Seq
IndexedSeq
Set
Map
A Seq will cover List, Vector etc, IndexedSeq will cover Vector etc etc. I found myself not using Iterable because I often need (or want) to know the size of the thing I have and back pre scala-2.8 Iterable did not provide access to this, so I kept having to turn things into sequences anyway!
Looks like Traversable and Iterable now have size methods so maybe I should go back to using them! Of course you could start "going mad" with GenTraversableOnce but that is not likely to aid in readability.
I have read the blog post recommended me here. Now I wonder what some those methods are useful for. Can you show examples of using forall (as opposed to foreach) and toList of Option?
map: Allows you to transform a value "inside" an Option, as you probably already know for Lists. This operation makes Option a functor (you can say "endofunctor" if you want to scare your colleagues)
flatMap: Option is actually a monad, and flatMap makes it one (together with something like a constuctor for a single value). This method can be used if you have a function which turns a value into an Option, but the value you have is already "wrapped" in an Option, so flatMap saves you the unwrapping before applying the function. E.g. if you have an Option[Map[K,V]], you can write mapOption.flatMap(_.get(key)). If you would use a simple map here, you would get an Option[Option[V]], but with flatMap you get an Option[V]. This method is cooler than you might think, as it allows to chain functions together in a very flexible way (which is one reason why Haskell loves monads).
flatten: If you have a value of type Option[Option[T]], flatten turns it into an Option[T]. It is the same as flatMap(identity(_)).
orElse: If you have several alternatives wrapped in Options, and you want the first one that holds actually a value, you can chain these alternatives with orElse: steakOption.orElse(hamburgerOption).orElse(saladOption)
getOrElse: Get the value out of the Option, but specify a default value if it is empty, e.g. nameOption.getOrElse("unknown").
foreach: Do something with the value inside, if it exists.
isDefined, isEmpty: Determine if this Option holds a value.
forall, exists: Tests if a given predicate holds for the value. forall is the same as option.map(test(_)).getOrElse(true), exists is the same, just with false as default.
toList: Surprise, it converts the Option to a List.
Many of the methods on Option may be there more for the sake of uniformity (with collections) rather than for their usefulness, as they are all very small functions and so do not spare much effort, yet they serve a purpose, and their meanings are clear once you are familiar with the collection framework (as is often said, Option is like a list which cannot have more than one element).
forall checks a property of the value inside an option. If there is no value, the check pass. For example, if in a car rental, you are allowed one additionalDriver: Option[Person], you can do
additionalDriver.forall(_.hasDrivingLicense)
exactly the same thing that you would do if several additional drivers were allowed and you had a list.
toList may be a useful conversion. Suppose you have options: List[Option[T]], and you want to get a List[T], with the values of all of the options that are Some. you can do
for(option <- options; value in option.toList) yield value
(or better options.flatMap(_.toList))
I have one practical example of toList method. You can find it in scaldi (my Scala dependency injection framework) in Module.scala at line 72:
https://github.com/OlegIlyenko/scaldi/blob/f3697ecaa5d6e96c5486db024efca2d3cdb04a65/src/main/scala/scaldi/Module.scala#L72
In this context getBindings method can return either Nil or List with only one element. I can retrieve it as Option with discoverBinding. I find it convenient to be able to convert Option to List (that either empty or has one element) with toList method.
So for example why does List(1,2,3,4).contains("wtf") even compile? Wouldn't it be nice if the compiler rejected this?
Lots of interesting answers, but here's my own theory: if contains did not receive an Any, then Seq could not be co-variant.
See, for instance, Set, which is not co-variant and whose contains take an A instead of an Any.
The reasons for that is left as an exercise to the reader. ;-) But here is a hint:
scala> class Container[+A](elements: A*) {
| def contains(what: A): Boolean = elements exists (what ==)
| }
<console>:7: error: covariant type A occurs in contravariant position in type A of value what
def contains(what: A): Boolean = elements exists (what ==)
^
"contains" is fundamentally about equality testing, and equality in Scala (as in Java before it) is untyped. The practical value of having untyped-equality is small, but not zero. There are, for instance, a few occasions where it makes sense for two objects of different classes to be equal to one another. For instance, you might wish an object of type RGBColor to be equal to a PantoneColor if they define the same hue, or an immutable HashSet and an immutable TreeSet to be equal if they contain the same elements. That said, untyped-equality also causes a bunch of headaches, and the fact that the compiler could easily catch that List(1,2,3,4).contains("wtf") is nonsensical but won't is one of them.
Most Java bug-finding tools include tests to detect the presence of improbable untyped-equality uses. (I wrote the inspections to do this in IntelliJ IDEA.) I have no doubt that when Scala bug-finding tools come online, these will be among the first bugs detected.
SeqLike.contains checks whether a value is present by checking for an element in the sequence that is equal to the value (using ==). == takes an Any so I suspect that this is the reason.