Erlang Mailing Lists

Author Message

<  Erlang questions mailing list  ~  Small poll

cpressey at catseye.mine.
Posted: Wed Dec 17, 2003 6:25 pm Reply with quote
Guest
On Wed, 17 Dec 2003 10:09:05 +0100
Bengt Kleberg <Bengt.Kleberg_at_ericsson.com> wrote:

> yes, i think i understand. you are saying that some code should be ok
> to compile, even if it will always crash at run time.
> would it seem very strange if i did not agree? because i do not, even
> though i have not ever written a compiler. perhaps this is why?

Bengt,

I could be wrong, but I think it is more likely that it's because you
aren't used to writing Erlang code in the "let it crash" style.

In this style, you write code very aggressively. You might have a
function like (this is just an example, not meant to do anything
useful:)

foo(Bar) ->
ok = file:setcwd(moo(Bar)),
{ok, File} = file:open(zoo(Bar)),
{ok, Records} = read_records(File),
ok = file:close(File),
Records.

So, the intent of the function is clearly to fail outright with
'badmatch' if anything goes wrong. foo/1's callers presumably wrap
their calls to foo (or their calls to whatever eventually calls foo) in
a catch. (Or the process that calls foo/1 is spawned, with the spawning
process linked/monitoring/trapping errors...)

The point is that foo/1 can fail, but that it's not *fatal*, in the
sense that the program keeps running.

Now what if we want a flag that disables this function? Maybe
eventually we'll read the flag from a file, but for testing purposes,
we'll just define it as a constant in the source:

baz_mode() -> true.

foo(Bar) ->
false = baz_mode(),
ok = file:setcwd(moo(Bar)), [...] Records.

Just as clearly as the previous example I hope, the intent of that line
of code is to disable the function if we are in baz mode, not to stop
the program from being compilable if we are in baz mode! :)

Where "let it crash" style is supported in Erlang, it's not always
graceful ('try' may improve that, if it ever gets added,) but it usually
results in much clearer code, because the assumptions/assertions are
made explicit.

But even if you don't use it, you have to recognize that many
programmers do, and for the "let it crash" style to work, code has to be
allowed to crash at runtime, even when it "can't be right".

-Chris


Post generated using Mail2Forum (http://m2f.sourceforge.net)
jamesh at Volition-inc.co
Posted: Wed Dec 17, 2003 7:48 pm Reply with quote
Guest
I've been following this thread with interest.

My gut feeling is that it's a can of worms that's best left closed. Why
warn about this case, but not slightly more complex cases? Depending on the
kind of optimizations the compiler does, you might be able to get warnings
about some of the these, but you'll still never get constant propagation
across module boundaries, for example. And "a + 42" as a legitimate mistake
on the programmer's part is much, much rarer than a simple fat-fingering of
the name of a function in a another module and having the compiler accept it
anyway (note: I'm not suggesting that this should be addressed!).

James


Post generated using Mail2Forum (http://m2f.sourceforge.net)
pascal.brisset-ml at wana
Posted: Wed Dec 17, 2003 8:14 pm Reply with quote
Guest
Chris Pressey writes:
> foo(Bar) ->
> ok = file:setcwd(moo(Bar)),
> {ok, File} = file:open(zoo(Bar)),
> {ok, Records} = read_records(File),
> ok = file:close(File),
> Records.
>
> So, the intent of the function is clearly to fail outright with
> 'badmatch' if anything goes wrong. foo/1's callers presumably wrap
> their calls to foo (or their calls to whatever eventually calls foo) in
> a catch. [...]

Note that if foo/1's caller catches failures from read_records/1,
file descriptors will be leaked. Days later, the beam process runs
out of descriptors and strange things happen. Been there.

What would seasoned Erlangers recommend to avoid this ?

-- Pascal



Post generated using Mail2Forum (http://m2f.sourceforge.net)
cpressey at catseye.mine.
Posted: Wed Dec 17, 2003 8:27 pm Reply with quote
Guest
On Wed, 17 Dec 2003 21:17:35 +0100
Pascal Brisset <pascal.brisset-ml_at_wanadoo.fr> wrote:

> Chris Pressey writes:
> > foo(Bar) ->
> > ok = file:setcwd(moo(Bar)),
> > {ok, File} = file:open(zoo(Bar)),
> > {ok, Records} = read_records(File),
> > ok = file:close(File),
> > Records.
> >
> > So, the intent of the function is clearly to fail outright with
> > 'badmatch' if anything goes wrong. foo/1's callers presumably wrap
> > their calls to foo (or their calls to whatever eventually calls
> > foo) in a catch. [...]
>
> Note that if foo/1's caller catches failures from read_records/1,
> file descriptors will be leaked. Days later, the beam process runs
> out of descriptors and strange things happen. Been there.
>
> What would seasoned Erlangers recommend to avoid this ?

Well, I am not a seasoned Erlanger[1], but I imagine most of them would
recommend spawning foo/1 into it's own process, then monitoring it or
linking to it. Then, when the process running foo/1 dies, its
filehandles and other resources will be deallocated (IIRC.)

-Chris

[1] I just come with a little wasabi on the side.


Post generated using Mail2Forum (http://m2f.sourceforge.net)
luke at bluetail.com
Posted: Wed Dec 17, 2003 8:32 pm Reply with quote
Guest
James Hague <jamesh_at_Volition-inc.com> writes:

> And "a + 42" as a legitimate mistake on the programmer's part is
> much, much rarer than a simple fat-fingering of the name of a
> function in a another module and having the compiler accept it
> anyway (note: I'm not suggesting that this should be addressed!).

I guess xref addresses this.

There's also a compiler option I've been wanting that could handle
it. I would like an option to generate a M:module_info(calls) that
returns a list of calls made by each function in the module.

Returns: [{Function, Arity, [Callee]}]
Callee = {Module, Function, Arity}

This way it would be easy to write a program that loads all modules in
the code path and reports all calls to functions that can't be found.

(I must admit that I rarely have this particular problem, possibly
because I use M-TAB and M-/ to complete my function names.)

I really want it as a way to write a who_calls(M,F,A)->[{M,F,A}]
function that could be used by Emacs for a "reverse tags lookup".
who_calls would expect all relevant modules to be loaded and do a fold
over them to find all callers. Then I can present the results in a
"hyperlinked" buffer and save myself a lot of grep'ery.

I've been meaning to hack this up as a parse transform using
syntax_tools and use it in the Jungerl. But if it's something the OTP
group would be interested in, I could look at putting it in the
compiler..?

-Luke



Post generated using Mail2Forum (http://m2f.sourceforge.net)
kostis at user.it.uu.se
Posted: Wed Dec 17, 2003 11:01 pm Reply with quote
Guest
James Hague wrote:
> I've been following this thread with interest.
>
> My gut feeling is that it's a can of worms that's best left closed.
> Why warn about this case, but not slightly more complex cases?

Sorry to suddently turn this thread into a political one, but the
above argument seems to me an argument of the form:

"Why try to eliminate some social injustices, since we are never
going to eliminate them all (especially the most subtle ones)."

Just think about it...

Cheers,
Kostis.



Post generated using Mail2Forum (http://m2f.sourceforge.net)
jamesh at Volition-inc.co
Posted: Wed Dec 17, 2003 11:31 pm Reply with quote
Guest
Kostis Sagonas wrote:
> > My gut feeling is that it's a can of worms that's best left closed.
> > Why warn about this case, but not slightly more complex cases?
>
> Sorry to suddently turn this thread into a political one, but the
> above argument seems to me an argument of the form:
>
> "Why try to eliminate some social injustices, since we are never
> going to eliminate them all (especially the most subtle ones)."
>
> Just think about it...

First, you can't compare software and social injustices. You just can't.
Well, okay, you just did, but it's not meaningful :)

Second, software is a battle against complexity. In this particular case
you're adding a check and a warning about something that's (A) a rare
occurrence, (B) going to bomb out immediately the first time you test the
function, and (C) detected at compile time in specific circumstances and not
detected in others. To provide a warning for this, you are adding
additional code to the compiler. Is it worth it?

I would buy that, yes, it makes sense because "a + 42" is a typical newbie
mistake, and we're probably not talking about a lot of additional code to
warn about this. But it's also a typical newbie mistake to use an atom in a
function header, like "first({x,y}) -> x", and that can't be warned against.
So it's hit-or-miss about what can be warned about and what can't. This is
what I meant about a can of worms. It is more straightforward to dismiss
the issue, rather than going down a long road of adding warnings for all
kinds of things that may or may not be errors, because realistically this is
a minor issue.

Again, this has nothing to do with social injustices. You don't engineer
laws the same way you engineer software.

James


Post generated using Mail2Forum (http://m2f.sourceforge.net)
kostis at user.it.uu.se
Posted: Wed Dec 17, 2003 11:52 pm Reply with quote
Guest
James Hague wrote:
> >
> > "Why try to eliminate some social injustices, since we are never
> > going to eliminate them all (especially the most subtle ones)."
> >
> > Just think about it...
>
> First, you can't compare software and social injustices. You just can't.

First of all, I am not comparing them with "software" but with
"software errors". To me, the analogy is a very good one.
In the same way that we cannot eliminate all social injustices,
we cannot eliminate all software errors. However, trying to is
a worthwhile cause, and achieving partial success is probably
better than doing nothing about it. The analogy is even better
if you take into account that most often than not, there is no
unanimous agreement about what really constitutes an injustice
or an error.

> Second, software is a battle against complexity. In this particular case
> you're adding a check and a warning about something that's (A) a rare
> occurrence, (B) going to bomb out immediately the first time you test the
> function, and (C) detected at compile time in specific circumstances and not
> detected in others. To provide a warning for this, you are adding
> additional code to the compiler. Is it worth it?

You are obviously not a compiler writer, are you? In this particular
case, we are actually talking about *eliminating* (in the case of the
BEAM compiler) and *avoiding adding* (in the case of HiPE) lots of
stupid code that is now special-handling the case of "a+42" (and
generating instructions with very weird argument types). If you
do not believe me, just look at the sources.

Best,
Kostis.



Post generated using Mail2Forum (http://m2f.sourceforge.net)
Bengt.Kleberg at ericsson
Posted: Thu Dec 18, 2003 9:15 am Reply with quote
Guest
Luke Gorrie wrote:
...deleted
> There's also a compiler option I've been wanting that could handle
> it. I would like an option to generate a M:module_info(calls) that
> returns a list of calls made by each function in the module.
>
> Returns: [{Function, Arity, [Callee]}]
> Callee = {Module, Function, Arity}
>
> This way it would be easy to write a program that loads all modules in
> the code path and reports all calls to functions that can't be found.

this would be a very good thing to have as a helper. today i manage by
cheating. i am not using the code path, but the source code directly.


> (I must admit that I rarely have this particular problem, possibly
> because I use M-TAB and M-/ to complete my function names.)

in wily one can cut-and-paste with a mouse chord. it is rare to write
any text more than once. different solution to the same problem.


> I really want it as a way to write a who_calls(M,F,A)->[{M,F,A}]
> function that could be used by Emacs for a "reverse tags lookup".
> who_calls would expect all relevant modules to be loaded and do a fold
> over them to find all callers. Then I can present the results in a
> "hyperlinked" buffer and save myself a lot of grep'ery.

would this find:
erlang:apply( module, function, [arg]),

my current grep on the source will find it.

and ofcourse, the real problem:
Module:Function(Arg)

any ideas on how to find these without running the code?


bengt


Post generated using Mail2Forum (http://m2f.sourceforge.net)
Bengt.Kleberg at ericsson
Posted: Thu Dec 18, 2003 9:29 am Reply with quote
Guest
Chris Pressey wrote:
...deleted
> In this style, you write code very aggressively. You might have a
> function like (this is just an example, not meant to do anything
> useful:)
>
> foo(Bar) ->
> ok = file:setcwd(moo(Bar)),
> {ok, File} = file:open(zoo(Bar)),
> {ok, Records} = read_records(File),
> ok = file:close(File),
> Records.

in this case i think the compiler will complain about read_records/1
beeing unknown :-)

seriously, if i have a module which _only_ contains (exported) functions
that will always fail at runtime i do think the compiler should refuse
to compile it.
(btw: i think the compiler should refuse to compile a module without any
exported functions, too)
if some of the (exported) functions might work at runtime, then the
compiler should compile, but warn about the always failing functions.

...deleted

> But even if you don't use it, you have to recognize that many
> programmers do, and for the "let it crash" style to work, code has to be
> allowed to crash at runtime, even when it "can't be right".

yes, i am all for letting code crash. i just do not think it is usefull
to let the compiler produce code for a module that will always crash
because potentially correct code is written in such a way as to produce
a runtime error.

use
erlang:throw/1
or
erlang:exit/1
if an runtime error is what you want.


bengt


Post generated using Mail2Forum (http://m2f.sourceforge.net)
jamesh at Volition-inc.co
Posted: Thu Dec 18, 2003 2:25 pm Reply with quote
Guest
Kostis Sagonas wrote:
>
> In this particular
> case, we are actually talking about *eliminating* (in the case of the
> BEAM compiler) and *avoiding adding* (in the case of HiPE) lots of
> stupid code that is now special-handling the case of "a+42" (and
> generating instructions with very weird argument types). If you
> do not believe me, just look at the sources.

But you're only getting this win if you make this an error, not a warning,
right? You'll still be "generating instructions with weird argument types"
if you print a warning, then generate code. In fact, you're *adding* (what
I suspect is a trivial amount of) code to print the warning.

James


Post generated using Mail2Forum (http://m2f.sourceforge.net)
kostis at user.it.uu.se
Posted: Thu Dec 18, 2003 2:32 pm Reply with quote
Guest
James Hague wrote:
>
> But you're only getting this win if you make this an error,
> not a warning, right?

It should then come as to no suprise that I have made a case
for the error over the warning in a previous mail of mine.

Kostis.



Post generated using Mail2Forum (http://m2f.sourceforge.net)
bjorn at erix.ericsson.se
Posted: Thu Dec 18, 2003 2:55 pm Reply with quote
Guest
When you print the error message, do you intend to
print the line number of the offending expression in the
source code?

/Bjorn

Kostis Sagonas <kostis_at_user.it.uu.se> writes:

> James Hague wrote:
> >
> > But you're only getting this win if you make this an error,
> > not a warning, right?
>
> It should then come as to no suprise that I have made a case
> for the error over the warning in a previous mail of mine.
>
> Kostis.
>

--
Bj
kostis at user.it.uu.se
Posted: Thu Dec 18, 2003 3:52 pm Reply with quote
Guest
> When you print the error message, do you intend to print the
> line number of the offending expression in the source code?

If possible, of course.

When HiPE compiles code as a JIT (i.e. starting from BEAM code)
this is not possible. When hipe compiles starting from source
through Core Erlang, the line numbers will of course be printed.

Kostis.



Post generated using Mail2Forum (http://m2f.sourceforge.net)
cpressey at catseye.mine.
Posted: Thu Dec 18, 2003 11:26 pm Reply with quote
Guest
On Thu, 18 Dec 2003 10:29:06 +0100
Bengt Kleberg <Bengt.Kleberg_at_ericsson.com> wrote:

> Chris Pressey wrote:
> > But even if you don't use it, you have to recognize that many
> > programmers do, and for the "let it crash" style to work, code has
> > to be allowed to crash at runtime, even when it "can't be right".
>
> yes, i am all for letting code crash. i just do not think it is
> usefull to let the compiler produce code for a module that will always
> crash because potentially correct code is written in such a way as to
> produce a runtime error.
>
> use
> erlang:throw/1
> or
> erlang:exit/1
> if an runtime error is what you want.

You're of course entitled to hold any opinion you wish, but I really
have to say that I disagree, and that I can't quite see your reasoning.

In Erlang as we know it, a + 42 generates an exception. An exception is
by definition not a show-stopper; it can be caught and acted upon. But
by changing it into a compile-time error, you're not even giving the
program an *opportunity* to crash. This runs against the "let it crash"
philosophy in my book.

Also, by forcing the programmer to write throw(blah) to cause an
exception, you're making them *make* it crash, which also runs counter
to "let it crash" - the programmer needn't exert such explicit effort.

To once again attempt to illustrate the difference:

foo() = (catch bar()).
bar() ->
true = some_assertion_which_may_or_may_not_be_constant(),
stuff().

...versus...

foo() = (catch bar()).
bar() ->
case some_assertion_which_may_or_may_not_be_constant() of
true -> stuff();
false -> throw(badarg)
end.

I'd much rather write (and read) the first version than the second.
Maybe it's just me, but I think it's more concise, more direct, and just
generally clearer. I also don't think it makes sense for the
compilation itself to succeed or fail based solely on whether
some_assertion_which_may_or_may_not_be_constant() is (detectably)
constant or not. That's why I'd much rather it be merely a compile-time
warning.

I'm all for getting as much information about possible errors as early
as possible - but I'm not in favour of dramatic shifts in how this
information would affect what is and what is not "legal Erlang".

-Chris



Post generated using Mail2Forum (http://m2f.sourceforge.net)

Display posts from previous:  

All times are GMT
Page 4 of 6
Goto page Previous  1, 2, 3, 4, 5, 6  Next
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum