Tuesday, March 13, 2007

Progress on Progress?

In the past few days, I have been exploring a side alley of the main topics in Cohatoe: progress monitoring. I think it would be actually nice to have something like a progress monitor API on the Haskell side so that you can send back progress feedback to the omnipresent progress dialogs in Eclipse (and by the way, Eclipse users are very much used to a responsive UI that allows them to send everything into the background that takes more than a few hundred milliseconds time). So I poked around in that area for a while. But it looks as if I have hit a dead end.

On the Java side, taking progress messages and pass them on to an IProgressMonitor instance isn't a real problem (although it took a bit to implement, mostly for the message encoding and decoding). But I'm somewhat stuck on the Haskell side.

Once more, this is more a question of API design than anything else. I don't think there would be a problem at all if we would in general pass a progress monitor 'handle' to the main entry point function. An example would then look like so:


import Cohatoe.API

resource = plugin {
pluginMain = sayHello
}

sayHello :: ProgressMonitor -> [String] -> [String]
sayHello _ _ = ["Hello from Haskell"]
that is, adding another parameter to the signature of the main entry point function. The progress monitor type would be declared by the Cohatoe API, and the framework would actually create a channel behind that value that sends all progress feedback to the Eclipse side.

However, I'm uneasy with that. True, there will be a lot of occasions where it makes sense to send progress feedback, but there will be as may where it seems not necessary. Of course, in these cases one can always ignore the progress monitor argument, but it still seems not nice to me to make it a part of the function signature everytime. I would very much more like something similar to this
myFunction :: [String] -> IO [String]
myFunction args = do
pm <- getProgressMonitor
pmBegin pm "Starting" 100
-- actually do something
pmDone pm
But then where to get the progress monitor from? I have tried some approaches that seemed to lead nowhere. I suspect I could do it by designing my own monad, but I'm not deep enough into Haskell yet to do that :-) And I also can't see how that would keep the API neat. So I think for now I'll leave the progress monitoring out in the interest of simplicity and revert the code base.

(Btw, this was more of an experiment anyway; I don't think that it is a good idea in general to re-model the Eclipse APIs, such as the progress monitors, in Haskell. That's far too much work, and there is a limit anyway, since the Eclipse APIs really assume to be dealing with stateful objects all the time. I've written a bit more about that in my earlier contribution to the Eclipse Languages Symposium.)

3 comments:

Thiago Arrais said...

My gut feeling is that a custom Monad is the way to go. That way cohatoe users would have access to progress monitoring when they wanted and will be able to escape the monada whenever they don't need it. Just like what happens with the IO monad.

Besides that, the monad would allow further modification on the API with less hassle. Addition of other monadic functions, for example, will not change the main function interface while inserting extra parameters into it will.

Maybe it would be a good idea to start a discussion on haskell-cafe on that subject. People there will certainly have all sorts of opinions and alternative solutions.

Leif Frenzel said...

Yes, for the sake of finding a solution out of interest :-)

Actually, I'm more and more convinced that it would not be good to have the APIs constrained for a re-modelled Eclipse API, at least not for progress monitors. Granted, progress monitors are deeply in the core in Eclipse, and they are nearly everywhere (resource change notifications, builders, jobs ... you name it). So it would be a nice shortcut. But it would't be a good general solution.

Leif Frenzel said...

Oh, perhaps to rephrase this a bit (re-reading my previous comment, I think it's not too clear :-)

I think that in general calling back from the Haskell side is one of the hard problems for Cohatoe. Progress Monitors are very basic and there seems to be a relatively easy solution to enable calling them, but this would involve a bit of 'hardcoding' their API on the Haskell side (what I have called 're-modelling'). In particular, I have written a ProgressMonitor data type and a set of functions on it that mimick the IProgressMonitor API. Plus I had to extend the communication between the Haskell server (the native process that executes the Haskell functions) and the corresponding Eclipse plugin that calls it. I had to build in some mechanism that 'knows' about the progress monitoring messages that are exchanged in between the initial call (Eclipse => Haskell) and the return value passing (Haskell => Eclipse). Clearly that doesn't scale.

The second hard problem is of course data marshalling. This is somewhat related to the question of accessing the Eclipse APIs from Haskell. At some point, there will be an interest to marshal Eclipse data structures to Haskell and back. And ideally, there would be an automatic mechanism to do so.

These are not the only interesting problems of course :-) However, the current solution works (although without progress monitoring, which looks a bit like an overreach for me right now). I think it will work just fine for things like 'mark occurrences' (I have just started to implement that as an example) or integrating the Haskell Refactorer.