Sunday 22 November 2009

Beware! scala.swing.TextField proclaims EditDone when it isn't

Update: Forget about EditDone. See Update below!

scala.swing.TextField is a basic GUI component that can be used for
letting the user input a line of text. When listening to this component, one can react to an EditDone event:

// Inside some GUI component ...
val textField = new TextField(20)
contents += textField
listenTo(textField)

reactions += {case EditDone(`textField`) =>
println("Ok, searching DB for input "+ textField.text)
}
//...


Fine. Whenever the user (me) hits the Enter key, the message, "Ok,
searching for DB input ...", simulating a database search, is printed.

However, what happens when some unrelated software product suddenly
pops up a window while the user (me) is still inputting text into the
TextField? I tell you what: The evil, non-sentient contraption prints
the simulated search message --- just as if I had hit Enter.

When the TextField loses focus, it emits an EditDone event. But I'm
not done editing. I've only typed "a". I was about to type
"abecedarian". Now the silly thing will search the database for all
words containing the letter "a". I never told it to do that. This
happened just because some other, unrelated, ill-behaving program
grabbed the focus.

Of course, the focus may also be lost because the user voluntarily
changes windows (for instance, in order to Google for "abecedarian").

As far as I can tell, there is no sane way to tell an EditDone event
produced by the user (me) hitting Enter from an EditDone event
produced because the TextField component lost focus. This cannot be
right.

(A while ago, I asked about this on the Scala-user list. Not one single
answer from one single soul in the entire Universe. It feels lonely.)

(I'm using Scala 2.8.)

Update: Forget about EditDone.

What you should do, is not to listen to the TextField, but to TextField.keys. This way, you'll be able to catch a KeyPressed event, and check if the key pressed was Enter. Simple.

It's a bit tricky to figure out, however, since it's not in the TextField Scala docs (you'll have to find your way to scala.swing.Component). This is how it could look:
import swing._
import event._

//...

// Inside some GUI component ...
val textField = new TextField(20)
contents += textField

listenTo(textField.keys)

import Key._
reactions += {case KeyPressed(`textField`, Enter, _, _) =>
println("Ok, searching DB for input "+ textField.text)
}
//...


Thanks to Ingo Maier for explaining this.

Monday 16 November 2009

Source's getLines in Scala 2.8 now strips line end

In Scala 2.8 (not yet officially released), scala.io.Source has been updated.

When reading lines from a file, you do not longer need to trim the lines, since newlines are removed by default. The code to read lines from a file using Source may now look something like this (where fName is a file name (a string)):

val lines = io.Source.fromPath(fName) getLines()

If you want to specify the input file encoding to be UTF-8, you could try this:
val lines = io.Source.fromPath(fName)("UTF8") getLines()

When you look at the API documentation, you'll find that fromPath takes a Codec as a second implicit parameter. Through some mysterious conversion (or "implicit conversion"), you can call it with a string ("UTF8") instead, as in the example above.

Anyway, no more Source.fromFile(fName).getLines.map(_.stripLineEnd). Someone is improving Scala!

Monday 17 August 2009

Cracker: "Tired of coding Perl"

Perl is doomed.

Even Cracker is tired of it. The evidence is found in a song on their latest album, where they sing "I'm tired of coding Perl, tired of V.B.A."

Take a look some 30 seconds into the video. The guy browsing the mod_perl Developer's cookbook is not happy. The "Turn on, tune in, drop out with me" video is here.

Perl is doomed.

Wednesday 29 July 2009

Scala case classes don't have auxiliary constructors?

The lesson of today, is that Scala case classes don't appear to have auxiliary constructors.

In Scala, auxiliary constructors may be added to a class by defining a "this" method:


scala> class AClass(s1: String, s2: String) {
def this(s: String) = this(s, "default")
}
defined class AClass

scala> new AClass("hey")
res0: AClass = AClass@187b5ff


Look what happens when you try the same trick on a case class:

scala> case class ACaseClass(s1: String, s2: String) {
def this(s: String) = this(s, "default")
}
defined class ACaseClass

scala> ACaseClass("hey")
:7: error: wrong number of arguments for method apply: (String,String)ACaseClass in object ACaseClass
ACaseClass("hey")
^


The attempt at adding an auxiliary constructor compiles, but results in a runtime error.

Update: Oops, yes the can have auxiliary constructors --- see comment below, by jkriesten, straightening things out!

Update: Paul (see comment below) points to the following discussion on this topic http://www.scala-lang.org/node/976.

Tuesday 9 June 2009

Printing the Unicode code points of UTF8 characters (Scala)

Sometimes it is useful to be able to print the Unicode code point of a UTF8 character. (For instance, when you need to check if you mistakenly use a similar looking character instead of the one you're supposed to use.)

Using Scala's RichString's format method, you can create a string of a zero padded, four digit, hexadecimal Unicode number, for example of the 'ä' character, like this:

scala> "%04X".format('ä'.toInt)
res0: String = 00E4

scala>


Here's a related example, printing a tab separated list of some IPA (phonetic) characters and their Unicode code points in a format suitable for using in Scala/Java strings:
scala> "ɸβfvθðszʃʒʂʐçʝxɣχʁħʕʜ"\
.map(c => "%s\t\\u%04X".format(c, c.toInt))\
.foreach(println)
ɸ \u0278
β \u03B2
f \u0066
v \u0076
θ \u03B8
ð \u00F0
s \u0073
z \u007A
ʃ \u0283
ʒ \u0292
ʂ \u0282
ʐ \u0290
ç \u00E7
ʝ \u029D
x \u0078
ɣ \u0263
χ \u03C7
ʁ \u0281
ħ \u0127
ʕ \u0295
ʜ \u029C

scala>
(The line terminating backslashes in the Scala code are added to indicate the fact that the above is a one-liner that doesn't fit the page. Remove these and the newlines if you want to run the code in the Scala shell.)

Knowing the codepoints can be useful, e.g. when you don't want to or can't input non-ASCII characters into your code:
scala> var v = "\u0278"
v: java.lang.String = ɸ

scala>



In Java, it looks similar, but you have to cast your chars to ints:

String.format("%04X", (int) 'ä'), etc.

Tuesday 24 March 2009

The perils of changing the case of UTF8 strings

Below are a few examples of what happens to some just slightly exotic UTF8 strings when up-cased and then down-cased again. The German ß (Eszett) doesn't have an uppercase variant, and becomes two characters. The Greek Sigma has one uppercase variant, but two different lowercase versions: one word final (ς); one for other positions (σ) (explaining my not-so-very-amusing joke in an earlier post).

In the table below, you'll find two other Greek lowercase characters that don't like to be up-cased, ΰ and ΐ. These two characters ultimately become six (see the length columns).

Last, the Turkish variants of <i>, always trusty when it comes to creating confusion (in a computer). The last but one row is interesting, since the original string is severely damaged. In the last row, the proper locale ("tr") is used, and the same string ends up in a much better condition.

The table was generated using Scala (thus Java) strings. The column EqIgnoreCase reports the result of comparing the original string and the up-cased and then down-cased version of that string using Scala's/Java's equalsIgnoreCase. The two rightmost columns present the length of the string before and after changing the case up and down again.

OrigUpCase ↑UpDown ⇅EqIgnoreCaseOrigLenNewLen
ßSSssfalse12
ςσΣΣσςtrue22
ΰΐΫ́Ϊ́ΰΐfalse26
iİıIIİIIiiiitrue44
iİıIİİIIiiııtrue44


The lesson? Nothing special. That you can do terrible things to strings. That changing the case of strings may be an irreversible operation. That if you are to normalize some text into either lower or uppercase, you might need to decide what's most suitable for a given language. That it might be a good idea to keep the original strings after normalization. That using the correct locale might help. That I'm not a graphical designer (the table is hideous).

Sunday 8 March 2009

Scala: Reversing a string by up- and then downcasing it

Did you know that you can reverse a string by merely upcasing it and then downcasing it again? Here's an example:

scala> val s = "ςσσ"
s: java.lang.String = ςσσ

scala> s.toUpperCase.toLowerCase == s.reverse.toString
res0: Boolean = true

scala>

If you don't believe me, just copy and paste the two lines of code above into the Scala interpreter, and see it for yourself.

Thursday 5 March 2009

The Firebird database: Problem handling UTF8 characters

The 'Latin capital letter I with dot above', İ (Unicode 0130), strikes again! This innocent looking Turkish character seems to be reliable when it comes to breaking software that should be able to handle UTF8. (See also this post for a Java example.)

This time it breaks the Firebird database (in my case, v2.1.1 on a 64-bit Debian system). Downcasing some random characters in a database configured to handle UTF8 works fine:

SELECT LOWER('AӴЁΪΣƓ') FROM RDB$DATABASE

returns the expected string, aӵёϊσɠ.

However, when you throw in the trouble-making İ, everything blows up:

SELECT LOWER('AӴЁΪΣƓİ') FROM RDB$DATABASE
*** IBPP::SQLException ***
Context: Statement::Fetch
Message: isc_dsql_fetch failed.

SQL Message : -104
Invalid token

Engine Code : 335544849
Engine Message :
Malformed string

Slightly different input, generates a different error message:
SELECT LOWER('İA') FROM RDB$DATABASE
*** IBPP::SQLException ***
Context: Statement::Fetch
Message: isc_dsql_fetch failed.

SQL Message : -802
Arithmetic overflow or division by zero has occurred.

Engine Code : 335544321
Engine Message :
arithmetic exception, numeric overflow, or string truncation

There is an item on the Firebird user list, but without any answers so far.

Update: As mariuz points out in a comment below, this defect now seems to be fixed in an upcoming version. See this bug tracker item.

Tuesday 6 January 2009

Book: Real World Haskell (not much real world so far :)

I've just started to read Real World Haskell (the paper book). It seems like a nice book (except for a few irritating and confusing typos/mistakes at the start of the book).

However, I've read more than 100 pages so far, and still not a sign of any of the "real world" stuff promised by the title. I still don't know much or anything about IDE:s, how to compile the code, scripting, any practical details on how to structure your code into modules, or anything in that direction. So far, mostly (sometimes rather long-wined) discussions on specific (list) functions. One of the examples, end up in a conclusion that might be paraphrased as "by the way, don't use the function we've discussed the last few pages; in real world settings it doesn't work too well".

In the real world, you run into both needles and haystacks , occasionally, but that doesn't help making sense of

isInAny3 needle haystack = any (isInfixOf needle) haystack
And one more real world example of the kind zip3foobar "quux" and I may start losing interest... or just start screaming.

Well, the upcoming chapters have promising titles, so I guess I just have to keep reading. And I guess you have to start with the basics. Still, over 100 pages, and mostly foobars so far...

The book is available on-line.