[erlang-questions] My biggest beef with Erlang

Robert Virding rvirding@REDACTED
Wed Nov 28 17:36:35 CET 2007


Sorry, I think you are wrong there. You have a number of problems when
detecting/handling safe functions and calling user defined functions in
guards:

- It is relatively easy to work which local functions are safe, but when you
call another module you suddenly leaping without a safety net. Yes, you
could analyse that functions within modules but that would not guarantee
that at run-time this was so. It has nothing to do with if I explicitly call
a module or through a variable, at *run-time* I have no guarantees. This
would mean that you would either have to tag functions at compile time and
check at run-time or trap unsafe system calls.

- dict (and sets, gb_trees, array, etc ) is actually safe as it does no
destructive updates.

- if you were to detect unsafe functions/system calls then what would it
actually *mean* when you hit one. The guard is neither true nor false, just
unprovable. Today with only simple type and value tests this is not a
problem, for example "when 2 * A > 4" contains an implicit type test of A.

- it would make it difficult to functions from "unknown" modules as I would
not know if they were safe or not.

- it would mean that many tests which seem perfectly reasonable and used in
code would not be allowed in guards, and this would create confusion to the
poor user. Seriously.

- the semantics of error handling is different in guards from in expressions
(normal function calls). In a guard an error is handled as false while in a
normal function call it generates an error. That would mean you have to keep
track of where you are in a call-stack and know how to handle errors in this
case. For example the (trivial) function:

is_even(I) -> (I rem 2) == 0.

would have to know if it called from a guard or expression. You could wrap
user function calls in guards with a try but then I think it is getting a
bit heavy in the implementation.

- as Joe mentioned guards are just extensions of pattern matching and really
shouldn't be considered as anything else.

- allowing users to do dangerous thing like removing the is_guard_bif
checking would be very unsafe and seriously compromise the robustness of the
emulator.

- really all that is left are functions which just contain expressions which
are allowed in guards.

If you are going to come up with a definition of guards which contain calls
to user defined functions then you have cover *every* possible case. Just
doing for reasonable usage is not the problem, users are usually
unreasonable and will dream up cases which the poor language designer and
compiler writer never thought anyone would ever consider doing. We have had
this problem before.

It would probably be better to define a 'cond' which is an extension of 'if'
(i.e. lisp cond) which allows user defined functions in tests but does not
have the special error handling in guards.

Robert

On 27/11/2007, David Holz <david_holz@REDACTED> wrote:
>
>
> From: rvirding@REDACTED
> > I actually defy anyone to come up with a safe, consistent and
> *understandable* definition of
> > guards which allow user defined functions. It would also be nice if they
> were relatively easy
> > to implement. Joe, remember our ideas with pipes?
>
> Hmm, how hard is it really to define?  It seems to me to be exactly like
> C++ const propagation.  There are a few things which can mutate state
> (process dict, message send/receive, ets et al, etc):
>
> - If a function calls built-in state mutators anywhere in its body, it's
> not pure functional.
> - If a function calls any other function that isn't pure functional, it's
> not pure functional.
> - If a function calls any M:F via variables instead of explicitly, tag it
> as not pure functional. (to make it easy to implement for an initial
> revision)
> - Only pure functional functions can be called in guards.
>
> The only challenging part is the dynamic code loading, which has similar
> issues to the M:F variable situation.  Inside a guard context, M:F call
> syntax would have to check the purity of the function it's calling, which
> can be cached between code loads.  This is really a linking issue, though,
> and could be theoretically designed not to have any per-call overhead for
> explicitly stated m:f's.  I'm not saying it's dirt simple to implement, but
> the idea of contagiously propagating "non-functionalness" shouldn't be
> difficult to define.
>
> I, however, would like to see a setting or switch somewhere to just remove
> the "is_guard_bif" checking completely, leaving it up to me to not do
> anything stupid, without inflicting any extra load doing runtime guard
> checks.  I think it should be straightforward to recompile the compiler
> myself with "is_guard_bif(_,_) -> true." but I haven't bothered with that
> yet.
>
> _________________________________________________________________
> Share life as it happens with the new Windows Live.Download today it's
> FREE!
>
> http://www.windowslive.com/share.html?ocid=TXT_TAGLM_Wave2_sharelife_112007
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://www.erlang.org/mailman/listinfo/erlang-questions
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20071128/42ef8dfb/attachment.htm>


More information about the erlang-questions mailing list