- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
type mismatch error
Fri, 2011-03-25, 01:05
I am trying to convert to scala from java. I found that the transition
is much harder than I thought. I am now stocking at the error
message:
error: type mismatch:
found : Unit
required: (String) => ?
count +=1
What I am trying to do is to read a big file and only read the first
10 lines:
object Test {
def main(args: Array[String]) {
test()
}
def test() {
val src = scala.io.Source.fromFile("myFile")
var count = 0
while(count<10) {
src.getLines().foreach {
println ("test")
count += 1
}
}
}
}
I tried many online suggestions such as:
src.getLines().foreach {
println ("test")
count += 1
if(count > 10) return
}
breakable{
src.getLines().foreach {
println ("test")
count += 1
if(count > 10) break
}
}
and defining the test() function as test(): Unit = {...}
Every attempt gives me some error messages. Can anyone tell me how to
achieve the goal?
Thanks
Fri, 2011-03-25, 02:27
#2
Re: type mismatch error
Try:
Source.fromFile("myFile").getLines().take(10).foreach(println)
or if you like to go commando:
Source.fromFile("myFile).getLines() take 10 foreach println
Ken
Source.fromFile("myFile").getLines().take(10).foreach(println)
or if you like to go commando:
Source.fromFile("myFile).getLines() take 10 foreach println
Ken
Fri, 2011-03-25, 02:37
#3
Re: type mismatch error
On 25 March 2011 00:05, young <soushare.com@gmail.com> wrote:
I am trying to convert to scala from java. I found that the transition
is much harder than I thought. I am now stocking at the error
message:
error: type mismatch:
found : Unit
required: (String) => ?
count +=1
What I am trying to do is to read a big file and only read the first
10 lines:
object Test {
def main(args: Array[String]) {
test()
}
def test() {
val src = scala.io.Source.fromFile("myFile")
var count = 0
while(count<10) {
src.getLines().foreach {
println ("test")
count += 1
}
}
}
}
This code isn't doing what I think you think it's doing. The 'foreach' and 'while' are both loops, and the 'count < 10' test won't be performed until the inner loop has run to completion.
If all you're after is the first n elements of something, then you want the 'take' method:
import io.Source
def test: Unit = {
val src = Source fromFile "myFile"
src.getLines.take(10).foreach { println("test") } }
In Scala, almost anything involving a 'var' indicates imperative code, and should be viewed with caution to see if there's a more functional/declarative way of solving the same problem.
I tried many online suggestions such as:
src.getLines().foreach {
println ("test")
count += 1
if(count > 10) return
}
breakable{
src.getLines().foreach {
println ("test")
count += 1
if(count > 10) break
}
}
and defining the test() function as test(): Unit = {...}
Every attempt gives me some error messages. Can anyone tell me how to
achieve the goal?
Thanks
--
Kevin Wright
gtalk / msn : kev.lee.wright@gmail.comkev.lee.wright@gmail.commail: kevin.wright@scalatechnology.com
vibe / skype: kev.lee.wrightquora: http://www.quora.com/Kevin-Wright
twitter: @thecoda
"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra
Fri, 2011-03-25, 02:47
#4
Re: type mismatch error
On 25 March 2011 01:24, Ken Scambler <ken.scambler@gmail.com> wrote:
Try:
Source.fromFile("myFile").getLines().take(10).foreach(println)
or if you like to go commando:
Source.fromFile("myFile).getLines() take 10 foreach println
Ken
Better still...
(Source fromFile "myFile").getLines take 10 foreach println
:)
--
Kevin Wright
gtalk / msn : kev.lee.wright@gmail.com kev.lee.wright@gmail.commail: kevin.wright@scalatechnology.com
vibe / skype: kev.lee.wrightquora: http://www.quora.com/Kevin-Wright
twitter: @thecoda
"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra
Fri, 2011-03-25, 09:57
#5
Re: type mismatch error
On Thu, Mar 24, 2011 at 5:05 PM, young wrote:
> I am trying to convert to scala from java. I found that the transition
> is much harder than I thought. I am now stocking at the error
> message:
>
> error: type mismatch:
> found : Unit
> required: (String) => ?
> count +=1
As Adam Tistler noted, this specific error message is because foreach
requires a function as an argument. A function type is written
(paramtype[,...]) => resulttype . Here, there's one String parameter
(the line that was read) and the return type can be anything (it's
actually Unit, but anything can be converted to Unit) -- thus
'required: (String) => ?'. But rather than providing a function such
as {line => ...}, you provided a block, {... count += 1}. The value of
a block is the value of its last statement, which is count += 1 (thus
that's where error message occurs) which has type Unit -- thus 'found:
Unit'. Your other examples (which should otherwise work) all have the
same problem. If you go back and look at those online suggestions, I
think you'll see that they're all of the form foreach{ ... => ...}
Of course, as the other responses point out, the
easy/functional/idiomatic way to get the first n items in Scala is to
do away with the explicit loop and use take(n), which returns an
Iterator that stops after yielding the nth element.
Fri, 2011-03-25, 10:17
#6
Re: type mismatch error
On Thu, Mar 24, 2011 at 6:24 PM, Ken Scambler wrote:
> Try:
> Source.fromFile("myFile").getLines().take(10).foreach(println)
>
> or if you like to go commando:
>
> Source.fromFile("myFile).getLines() take 10 foreach println
>
> Ken
That's swell but it doesn't address why the OP got an error message.
It should be pointed out that these will get the same error message if
println is replaced with println("test") as in the original, because
the former is (convertable to) a function while the latter isn't. To
print "test" every time, one can use foreach { _ => println("test") },
and to actually do something with the read line (beyond passing it
implicitly as the argument to a unary method such as println), `_`
should be replaced with a parameter name.
Fri, 2011-03-25, 18:37
#7
Re: type mismatch error
Thanks for all the replies. They are very helpful.
What I really want to do is to read from a big file and get the top 10
lines with some condition (e.g., lines include the word "scala"), and
do something with the 10 lines. Now everything works good except I
can't get the breakable{} working. Do I have to break the code into
two functions and passing the data back and forth?
On Mar 25, 2:07 am, Jim Balter wrote:
> On Thu, Mar 24, 2011 at 6:24 PM, Ken Scambler wrote:
> > Try:
> > Source.fromFile("myFile").getLines().take(10).foreach(println)
>
> > or if you like to go commando:
>
> > Source.fromFile("myFile).getLines() take 10 foreach println
>
> > Ken
>
> That's swell but it doesn't address why the OP got an error message.
> It should be pointed out that these will get the same error message if
> println is replaced with println("test") as in the original, because
> the former is (convertable to) a function while the latter isn't. To
> print "test" every time, one can use foreach { _ => println("test") },
> and to actually do something with the read line (beyond passing it
> implicitly as the argument to a unary method such as println), `_`
> should be replaced with a parameter name.
>
Fri, 2011-03-25, 18:47
#8
Re: Re: type mismatch error
On 25 March 2011 17:29, young <soushare.com@gmail.com> wrote:
Thanks for all the replies. They are very helpful.
What I really want to do is to read from a big file and get the top 10
lines with some condition (e.g., lines include the word "scala"), and
do something with the 10 lines. Now everything works good except I
can't get the breakable{} working. Do I have to break the code into
two functions and passing the data back and forth?
(Source fromFile "myFile").getLines filter { _ endsWith "scala" } take 10 foreach doSomething
On Mar 25, 2:07 am, Jim Balter <J...@Balter.name> wrote:
> On Thu, Mar 24, 2011 at 6:24 PM, Ken Scambler <ken.scamb...@gmail.com> wrote:
> > Try:
> > Source.fromFile("myFile").getLines().take(10).foreach(println)
>
> > or if you like to go commando:
>
> > Source.fromFile("myFile).getLines() take 10 foreach println
>
> > Ken
>
> That's swell but it doesn't address why the OP got an error message.
> It should be pointed out that these will get the same error message if
> println is replaced with println("test") as in the original, because
> the former is (convertable to) a function while the latter isn't. To
> print "test" every time, one can use foreach { _ => println("test") },
> and to actually do something with the read line (beyond passing it
> implicitly as the argument to a unary method such as println), `_`
> should be replaced with a parameter name.
>
> -- Jim
--
Kevin Wright
gtalk / msn : kev.lee.wright@gmail.comkev.lee.wright@gmail.commail: kevin.wright@scalatechnology.com
vibe / skype: kev.lee.wrightquora: http://www.quora.com/Kevin-Wright
twitter: @thecoda
"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra
Fri, 2011-03-25, 21:07
#9
Re: type mismatch error
On Mar 25, 10:29 am, young wrote:
> What I really want to do is to read from a big file and get the top 10
> lines with some condition (e.g., lines include the word "scala"), and
> do something with the 10 lines. Now everything works good except I
> can't get the breakable{} working.
You really should use the simple, straightforward approach that
everyone else has described instead of mucking around with breakable.
Here's the idea, a step at a time instead of all strung out in one
function.
val src = Source.fromFile("myFile")
val lines = src.getLines()
val filtered = lines.filter {_.containsSlice("scala")}
val take10 = filtered.take(10)
for (line <- take10) println(line) // see if we got what we wanted
I think what you're missing is that the filter function on an Iterator
is non-strict, meaning that the resulting filtered Iterator won't ask
for any data from the underlying Iterator until the filtered Iterator
needs it to satisfy a request.
For that matter, the take function on an Iterator is also non-strict.
In the code above, nothing gets read until the "line <- take10"
generator starts asking for lines (not quite true: a character may
need to be read to determine whether or not "hasNext" is true or not
right off the bat, etc.). Anyway, the generator causes the take10
Iterator to ask for lines from the filtered Iterator, which in turn
asks for lines from the lines Iterator, which in turn asks for
characters from the BufferedSource. The take10 Iterator will stop the
reading once it's found the top 10 lines (if indeed there are 10 to be
found).
And now a surprise. If we go back and use take10 a second time,
nothing happens. It's already taken the 10 records in response to the
earlier request, and *it didn't store them*! If you try to create
another "filtered.take(10)" to start over, you'll read the records in
the file after the ones you've already read, which probably isn't what
you wanted.
In order to read *and store* the top 10 lines so that they can be
accessed multiple times, you need to add something like this:
val first10 = take10.toList
This forces the take10 Iterator to be run from start to finish and the
results *stored* in a List. The resulting List can be reused as often
as you want.
Now, suppose you want to have the results stored for later use, but
you don't want the lines read in if nobody ever needs them. For that
you'd use something like this:
val first10 = take10.toStream
A Stream won't read the data until it's needed, but once the data's
been read, the Stream stores it for repeated use.
One of the challenges of converting to Scala from non-functional
languages is getting comfortable with the different evaluation
strategies that are available: strict (evaluate immediately), non-
strict (re-evaluate every time it's needed), and lazy (evaluate when
needed, then save the result for later re-use). Consider these:
val strictTime = System.currentTimeMillis()
lazy val lazyTime = System.currentTimeMillis()
def nonStrictTime = System.currentTimeMillis()
The value of strictTime is the initialization time, and is constant.
The value of lazyTime is the time that it was first accessed, and is
constant. The value of nonStrictTime is the current time whenever it's
accessed, and is not constant.
Sat, 2011-03-26, 02:07
#10
Re: Re: type mismatch error
On Fri, Mar 25, 2011 at 10:29 AM, young wrote:
> Thanks for all the replies. They are very helpful.
>
> What I really want to do is to read from a big file and get the top 10
> lines with some condition (e.g., lines include the word "scala"), and
> do something with the 10 lines. Now everything works good except I
> can't get the breakable{} working. Do I have to break the code into
> two functions and passing the data back and forth?
Here's a fishing pole:
http://www.scala-lang.org/api/current/index.html
You should familiarize yourself with the classes and methods relevant
to your work, especially the collections. Specifically, see the
withFilter method of
http://www.scala-lang.org/api/current/scala/collection/TraversableLike.html
(click on withFilter to see the long description). (Note that filter
is the same as withFilter for Iterators.)
Another fishing pole is
http://www.artima.com/shop/programming_in_scala_2ed -- I strongly
recommend that you purchase this book. If you don't want to spend
money, there's also http://programming-scala.labs.oreilly.com/ , a
complete on-line free book about Scala.
Sat, 2011-03-26, 15:27
#11
Re: type mismatch error
On Mar 25, 6:04 pm, Jim Balter wrote:
> see the withFilter method of http://www.scala-lang.org/api/current/scala/collection/TraversableLike.html
> (click on withFilter to see the long description).
> (Note that filter is the same as withFilter for Iterators.)
The filter and withFilter methods are never the same because they
return very different types. The withFilter method won't do the job
here because its result type is a FilterMonadic, which only supports
the flatmap, foreach, map, and withFilter operations. The withFilter
method is provided mainly for internal use by for comprehensions.
The filter method, however, always returns an object of the same type
as it was called on. The task at hand is best implemented with a
take() function on the filtered output, which can be done on the
Iterator object returned by the Iterator.filter method but can't be
done on a FilterMonadic returned by the Iterator.withFilter method.
-------
Reading the docs and books is always a fine idea, but it's
surprisingly rare to find any discussion of the differences between
strict, non-strict, and lazy evaluation, and I think that's what was
tripping up the original poster. They didn't want their code to read
any more lines from the file than necessary, and because they didn't
realize that Iterator.filter was non-strict they were trying to find a
way to abort the reading. The API description for Iterator neglects to
mention that it's non-strict, so reading the API wouldn't have
answered the question. I suppose it's considered self-evident that
Iterator would have to be non-strict if you really think about it --
the Iterator might not just be on a big file, it could be on an
infinite sequence (Fibonacci numbers, for example).
It doesn't help that many discussions of strictness confuse non-strict
and lazy. An egregious example is in Odersky and Spoon's own
discussion of the 2.8 collections. http://www.scala-lang.org/docu/files/collections-api/collections_42.html
says, "A view is a special kind of collection that represents some
base collection, but implements all transformers lazily." No, a view
implements them non-strictly. A Stream implements them lazily. That's
the reason that collections have both toStream and view methods. As I
noted in my earlier posting, there's an important difference in
behavior between the non-strict Iterator.take(10) and the lazy
Iterator.take(10).toStream.
Sat, 2011-03-26, 16:47
#12
Re: Re: type mismatch error
On Sat, Mar 26, 2011 at 10:19 AM, Doug Pardee <dougpardee@yahoo.com> wrote:
Not actually surprising, though -- given that most languages people are exposed to don't have *either* concept in any principled way, so most folks are only exposed to at most one of them. (Usually lazy.) And the difference seems to be a tad subtle in practice.
For those who are scratching their heads about this distinction (as I was), here's a reasonably clear description in (unsurprisingly) the Haskell wiki:
http://www.haskell.org/haskellwiki/Lazy_vs._non-strict
It doesn't help that many discussions of strictness confuse non-strict
and lazy.
Not actually surprising, though -- given that most languages people are exposed to don't have *either* concept in any principled way, so most folks are only exposed to at most one of them. (Usually lazy.) And the difference seems to be a tad subtle in practice.
For those who are scratching their heads about this distinction (as I was), here's a reasonably clear description in (unsurprisingly) the Haskell wiki:
http://www.haskell.org/haskellwiki/Lazy_vs._non-strict
Sat, 2011-03-26, 20:47
#13
Re: Re: type mismatch error
On Sat, Mar 26, 2011 at 7:19 AM, Doug Pardee wrote:
> On Mar 25, 6:04 pm, Jim Balter wrote:
>> see the withFilter method of http://www.scala-lang.org/api/current/scala/collection/TraversableLike.html
>> (click on withFilter to see the long description).
>> (Note that filter is the same as withFilter for Iterators.)
>
> The filter and withFilter methods are never the same because they
> return very different types.
Ahem. From Iterator.scala:
def withFilter(p: A => Boolean): Iterator[A] = filter(p)
> The withFilter method won't do the job
> here because its result type is a FilterMonadic, which only supports
> the flatmap, foreach, map, and withFilter operations. The withFilter
> method is provided mainly for internal use by for comprehensions.
>
> The filter method, however, always returns an object of the same type
> as it was called on. The task at hand is best implemented with a
> take() function on the filtered output, which can be done on the
> Iterator object returned by the Iterator.filter method but can't be
> done on a FilterMonadic returned by the Iterator.withFilter method.
> -------
> Reading the docs and books is always a fine idea, but it's
> surprisingly rare to find any discussion of the differences between
> strict, non-strict, and lazy evaluation, and I think that's what was
> tripping up the original poster. They didn't want their code to read
> any more lines from the file than necessary, and because they didn't
> realize that Iterator.filter was non-strict they were trying to find a
> way to abort the reading.
No, that has nothing to do with what the OP was tripping up on -- he
wasn't even aware that there were such methods as take and filter; his
main source of trouble was that he didn't understand the difference
between a function and a block. This is clear from reading the
original post and noting what error message he received -- something
that most of the responses ignored in their rush to provide functional
one-liners. Even after everyone told him to use take, he was still
trying to write imperative loops using breakable.
> The API description for Iterator neglects to
> mention that it's non-strict, so reading the API wouldn't have
> answered the question.
The description of withFilter for Traversable *does* mention the
difference, and the description of withFilter for Iterator mentions
that filter and withFilter are the same for iterators. See, reading
the API can be helpful -- you should try it.
Sat, 2011-03-26, 21:27
#14
Re: Re: type mismatch error
P.S. ...
On Sat, Mar 26, 2011 at 12:46 PM, Jim Balter wrote:
> On Sat, Mar 26, 2011 at 7:19 AM, Doug Pardee wrote:
>> On Mar 25, 6:04 pm, Jim Balter wrote:
>>> see the withFilter method of http://www.scala-lang.org/api/current/scala/collection/TraversableLike.html
>>> (click on withFilter to see the long description).
>>> (Note that filter is the same as withFilter for Iterators.)
>>
>> The filter and withFilter methods are never the same because they
>> return very different types.
>
> Ahem. From Iterator.scala:
>
> def withFilter(p: A => Boolean): Iterator[A] = filter(p)
>
>
>> The withFilter method won't do the job
>> here because its result type is a FilterMonadic, which only supports
>> the flatmap, foreach, map, and withFilter operations. The withFilter
>> method is provided mainly for internal use by for comprehensions.
You're right that, *generally*, withFilter only supports those
methods, and so *generally* it can't be chained to take, and so I
should not have suggested its use here -- that's a good and valid
point. But you're wrong on the details, and before you naysay someone
you should take the time to verify your claim. When I wrote that
filter is the same as withFilter for Iterators, I had read that very
statement in the API just seconds earlier. You write that they "are
never the same because they return very different types", but you seem
to overlook that FilterMonadic is a trait. Iterator that doesn't mix
it in, but it could and probably should -- it only gets away with not
doing so because "for" is implemented by the compiler and it only
looks for a structural type match.
Sun, 2011-03-27, 15:57
#15
Re: type mismatch error
On Mar 26, 1:23 pm, Jim Balter wrote:
> You're right that, *generally*, withFilter only supports those
> methods, and so *generally* it can't be chained to take, and so I
> should not have suggested its use here -- that's a good and valid
> point. But you're wrong on the details
Oops. You're right. I shouldn't have made such a broad statement as
"never" the same. A further mea culpa: I made the mistake of assuming
that Iterator.withFilter would have the same signature as
Traversable.withFilter, since they're used identically by the for
comprehension. I learned something new, which is almost always a Good
Thing.
To try to perfume this pig, I'll note that my intent was to disagree
with recommending the use of the withFilter function, which IMO should
be pretty much ignored by Scala programmers. It's useful in for
comprehensions, but elsewhere, not so much. Yeah, good intentions and
the road to...
-------
On the other topic, I think we were addressing different postings.
Mine was in response to the "everything works good except I can't get
the breakable{} working" posting. For the original posting, your
comment that the OP "didn't understand the difference between a
function and a block" is right on point.
And yet... and yet... I'm not convinced that referencing the
documentation will fix that. I imagine that we'd all (for a relatively
large value of all) like to see Scala programmers using the idioms,
and naturally the various documentation tends to use Scala idioms
throughout. Unfortunately, the idioms are usually used without
explaining that they're idioms. I did it myself in my first posting on
this topic, when I suggested using filter{_.containsSlice("scala")}
without explaining that:
_.containsSlice("scala")
might look like an expression, but it's actually an anonymous-
parameter idiom for the function:
param => param.containsSlice("scala")
which uses the syntactic sugar of type inference, and of dropping the
parameter list parens with a single parameter, from the general
anonymous function form:
(param:String) => param.containsSlice("scala")
which is itself syntactic sugar for the instance of an anonymous
class:
new Function1[String,Boolean] {
def apply(param:String):Boolean = param.containsSlice("scala")
}
I certainly don't want to see people using the "new Function1" form;
it isn't idiomatic. And it's ugly, to boot. But knowledgeable Java
programmers will recognize and understand the anonymous class form.
Then the related idioms might make more sense for them. According to
me. :-)
I am no expert, however:
The foreach() method on Iterator accepts a function with one String param, so
This:
src.getLines().foreach {
println ("test")
count += 1
}
needs to be changed to:
src.getLines().foreach { line =>
println ("test")
count += 1
}
The compiler infers that line is of type String since you are operating on an object that inherits from Iterator[String]
On Mar 24, 2011, at 8:05 PM, young wrote:
> I am trying to convert to scala from java. I found that the transition
> is much harder than I thought. I am now stocking at the error
> message:
>
> error: type mismatch:
> found : Unit
> required: (String) => ?
> count +=1
>
> What I am trying to do is to read a big file and only read the first
> 10 lines:
>
> object Test {
> def main(args: Array[String]) {
> test()
> }
>
> def test() {
> val src = scala.io.Source.fromFile("myFile")
> var count = 0
> while(count<10) {
> src.getLines().foreach {
> println ("test")
> count += 1
> }
> }
> }
> }
>
> I tried many online suggestions such as:
>
> src.getLines().foreach {
> println ("test")
> count += 1
> if(count > 10) return
> }
>
> breakable{
> src.getLines().foreach {
> println ("test")
> count += 1
> if(count > 10) break
> }
> }
>
> and defining the test() function as test(): Unit = {...}
>
> Every attempt gives me some error messages. Can anyone tell me how to
> achieve the goal?
>
> Thanks