Adrian Hey wrote:

I'm puzzled about this idea of "module init action" in a declarative
language. Perhaps, if it's desirable to have some module initialisation
applied to a module if anything from it is used, the way to do this would
be to have a reserved identifier specially for the purpose, like
"main", but at the module level. (Though this idea still seems a
bit strange to me).

I don't see what's so strange about that. At least, it's not any stranger than on-demand execution of IO actions in a pure functional language. And the toplevel "<-" is definitely a natural syntax for that.


I've interpreted this correctly this means that someAction will always
get executed, whether or not foo (or anything dependent on foo) is used
elsewhere? This seems like a bad thing to me.

It's a feature. I'd actually _want_ to use that one independently.

It may be harmless enough
if all it does is create a few IORefs which are then promptly garbage
collected, but in some situations it could involve quite complex
and expensive initialisation operations on foreign libraries
(for example).

Well if you want those IO operations to be lazily interleaved with the rest of the program (or not executed at all), you can use


valueToBeInitedLazily <- unsafeInterleaveIO $ do
        blah

... which explicitly says what you are doing that might be slightly unsafe.

Since a lot of the concerns expressed about this seem to centre
around possible abuse of arbitrary IO operations in these top
level constructions, maybe the problem could be addressed by
insisting that a restricted monad was used, call it SafeIO say.

You're taking away a feature I want to use.
1) Initialising global IORefs is a good thing, no matter when it's actually done.
2) Being able to initialize things at program startup is a good thing, even if they're
not explicitly referred to.
3) Lazy, on-demand initialization of things is a good thing, if you know what you're doing.
4) Lazy, on-demand initialization of things (with potential side effects) is a bad thing, if you don't know what you're doing.


If we define toplevel IO bindings to be just like the unsafePerformIO hack, we get 1,3 and 4 (and 4 is actually a bad thing).
If we define toplevel IO bindings as mdo-style module initialisation, we get 1 and 2 directly, and 3 with an obvious use of unsafeInterleaveIO. We don't get 4, because obviously, when you use unsafeInterleaveIO, you're already claiming to know what you're doing.


Also note that if useless initialization of IORefs ever becomes a problem, we can still use lots of nasty hacks inside the compiler to optimize for those common functions. But I don't think we'll ever have to do this.

Cheers,

Wolfgang

_______________________________________________
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell

Reply via email to