From: Duncan C. <dun...@wo...> - 2004-07-13 12:51:13
|
On Tue, 2004-07-13 at 09:49, Axel Simon wrote: > On Mon, Jul 12, 2004 at 06:44:31PM +0100, Duncan Coutts wrote: > > Right the codes are only unique within each error domain. It's not > > obvious how to translate this into Haskell nicely. Obviously for each > > domain we could have a Haskell enum (we already do this in several > > places) but the GError we throw contains just the error code not the > > enum, because which enum we want depends on the error domain code. > > > > So at the moment to handle an error you'd need to do something like > > handleGErrorJustDomain errorDomainOfInterest > > (\GError dom code msg -> case toEnum code of > > FirstPossibility -> ... > > AnotherPossibility -> ... ) > > > > So we have to manually convert to the right enum depending on the error > > domain. > > I think this is ok because the most common case is that you want to handle > the errors of exacly one domain. Right, that would definitely be the common case. What I was hoping was that it would auto-magically convert to the right enum for the domain I was interested in handling. Something like: handleGErrorJustDomain :: GErrorDomain errorEnum => IO a -> (errorEnum -> ErrorMessage -> IO a) -> IO a So the handler only deals with one error domain enum. From that, the handler function figures out which error domain code to look for. That would suggest a type class scheme like so: class Enum err => GErrorDomain err where gerrorDomain :: err -> GErrorDomainCode instance GErrorDomain GdkPixbufLoaderError where gerrorDomain _ = unsafePerformIO {#call unsafe pixbuf_error_quark#} handleGErrorJustDomain would be implemented something like: catchGErrorJustDomain action (handler :: err -> String -> IO a) = catchGError action handler' where handler' gerror@(GError domain code msg) | domain == gerrorDomain (undefined::err) = handler (toEnum code) msg | otherwise = throwGError gerror > > Perhaps another cunning type class based scheme would solve it? > > class GErrorDomain where > > ??? > > instance GErrorDomain GdkPixbufLoaderError where > > ??? > > Yes, perhaps that works. If GError had a fake type parameter which > is GdkPixbufLoaderError for the specific class, does that work with the > dynamic types? You mean like: data GError dom = GError GErrorDomainCode GErrorCode String So you can have GError GdkPixbufLoaderError. Of course then the GErrorDomainCode does not need to be stored in the GError since it can be found from the type parameter. I'm not sure about dynamic types like this, it just needs a quick experiment. > > At the moment people just call initGUI & mainGUI which are not suitable > > for installing error handlers because they return rather than taking a > > continuation. > > So true. Perhaps we should add such a function runGUI :: IO a -> IO a runGUI main = do initGUI catchGError main (\GError -> ...) mainGUI On the other hand initialisation gets more complicated (requires more parameters) once we add other gnome libs into the mix. We might want to hold off creating new initialisation APIs until the requirements become clearer. > There is a silent exception handler wrapped around each callback, hence > GHC will abort the program if an exception occurs in a callback. But since > we are generating all the signal handlers automatically, we could add our > own 'catch' statement that calls an exception handler in some global > variable. I suppose there aren't that many possibilities of raising > GErrors in the main program, are they? In that case, a global error > handler might be the cleanest thing. The only problem is that it is not > clear how to determine the return value after an exception has been raised > within a callback. It might be sufficient to simply terminate the program with a helpful error message. At least that gives people the chance of handling the error if they want to or in a throwaway program to at least get some diagnostic. Then we can avoid the issue of returning something in the case that an error was thrown. Afterall, ghc just terminates the program in the case of an unhandled exception, abeit only at the top level rather than in each signal handler as we'd do. > > > P.S.: I gave up on the automake thing. There was only a slight chance to > > > get it to work by compiling each .hs file to .o before linking. However > > > all the c2hs stuff and the packaging is quite difficult and requires > > > modifying automake (which is written in Perl and as far as I can see > > > cannot be extended without modifying automake itself). I will streamline > > > some configuration stuff, though. While looking at that, I'd suggest looking at whether it'd be better to keep package.conf files in each directory that builds into a package rather than generating them from the makefile. It'd allow easier per-package modifications, also I found when packaging a number of libs for Gentoo that using actual .conf files made modifying the install location rather easier. ghc's ghc-pkg allows some template mechanisms that it expands when the .conf file is merged into the global pacage.conf file. BTW I remember some extra effort needed in the makefiles to strip out directories that don't exist from the package.conf files because otherwise ghc-pkg would complain. I just noticed that there is a --force option that will make ghc-pkg not check for non-existent directories. Duncan |