EEP 47: Syntax in try/catch to retrieve the stacktrace directly

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

EEP 47: Syntax in try/catch to retrieve the stacktrace directly

Björn Gustavsson-4
There is a new EEP that proposes a new syntax in try/catch to retrieve
the stacktrace directly without using erlang:get_stacktrace/0:

https://github.com/erlang/eep/blob/master/eeps/eep-0047.md

/Björn
--
Björn Gustavsson, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: EEP 47: Syntax in try/catch to retrieve the stacktrace directly

Jesper Louis Andersen-2
I think this is a sensible change all in all, and one which should be done.

My major gripe with it is the fact that you cannot pattern match on the stack trace. I see why this is done, but it feels like being a special arbitrary rule which goes against other matching patterns in the language. I'm not sure how it would help

catch
   Cl:Err:Stk ->
        case {Cl, Err, Stk} of
          ...
end

What I really like about the change is that it removes get_stacktrace/0 which is a "bad function", and one of those things I tend to call a "language mistake" in Erlang[0].

[0] For the interested, I think one of the most obvious mistakes are that a floating point numbers in Erlang cannot express NaNs and Infinities.

On Fri, Nov 24, 2017 at 10:05 AM Björn Gustavsson <[hidden email]> wrote:
There is a new EEP that proposes a new syntax in try/catch to retrieve
the stacktrace directly without using erlang:get_stacktrace/0:

https://github.com/erlang/eep/blob/master/eeps/eep-0047.md

/Björn
--
Björn Gustavsson, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: EEP 47: Syntax in try/catch to retrieve the stacktrace directly

Attila Rajmund Nohl
Once I worked with a library that implemented the "let it crash"
philosophy to the maximum - for valid input I got the result, for
invalid input I got function_clause, badarg, badmatch, etc. crashes. I
tried to be clever and match on the output of erlang:get_stacktrace()
to decide if the error came from this particular library or from a
different code (in order to provide more meaningful error message to
the user), but eventually it didn't work out. In that case matching on
the stack trace might have been useful, but as it didn't work out in
the end, I don't think it's such a big deal that I can't match on the
stacktrace.

2017-11-25 15:17 GMT+01:00 Jesper Louis Andersen
<[hidden email]>:

> I think this is a sensible change all in all, and one which should be done.
>
> My major gripe with it is the fact that you cannot pattern match on the
> stack trace. I see why this is done, but it feels like being a special
> arbitrary rule which goes against other matching patterns in the language.
> I'm not sure how it would help
>
> catch
>    Cl:Err:Stk ->
>         case {Cl, Err, Stk} of
>           ...
> end
>
> What I really like about the change is that it removes get_stacktrace/0
> which is a "bad function", and one of those things I tend to call a
> "language mistake" in Erlang[0].
>
> [0] For the interested, I think one of the most obvious mistakes are that a
> floating point numbers in Erlang cannot express NaNs and Infinities.
>
> On Fri, Nov 24, 2017 at 10:05 AM Björn Gustavsson <[hidden email]> wrote:
>>
>> There is a new EEP that proposes a new syntax in try/catch to retrieve
>> the stacktrace directly without using erlang:get_stacktrace/0:
>>
>> https://github.com/erlang/eep/blob/master/eeps/eep-0047.md
>>
>> /Björn
>> --
>> Björn Gustavsson, Erlang/OTP, Ericsson AB
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
>
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
>
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: EEP 47: Syntax in try/catch to retrieve the stacktrace directly

Richard Carlsson-3
I agree that this is a good change. I can't even recall exactly why we went with the get_stacktrace() BIF - particularly since the value is already present as a variable under the hood. But I guess it was precisely to avoid such discussions about pattern matching on stack traces or having arbitrary restrictions such as "may only be a variable" on a part of a pattern. But I think such a restriction makes sense.

The main problem with code that matches on the format of the stack trace is that it creates a hard dependency on the current format of the stack trace - which has changed more than once and might change again. The general rule is Don't Do That, and if you still feel that you have to, at least limit it to a single support function, not spread all over your code.

        /Richard

2017-11-26 14:40 GMT+01:00 Attila Rajmund Nohl <[hidden email]>:
Once I worked with a library that implemented the "let it crash"
philosophy to the maximum - for valid input I got the result, for
invalid input I got function_clause, badarg, badmatch, etc. crashes. I
tried to be clever and match on the output of erlang:get_stacktrace()
to decide if the error came from this particular library or from a
different code (in order to provide more meaningful error message to
the user), but eventually it didn't work out. In that case matching on
the stack trace might have been useful, but as it didn't work out in
the end, I don't think it's such a big deal that I can't match on the
stacktrace.

2017-11-25 15:17 GMT+01:00 Jesper Louis Andersen
<[hidden email]>:
> I think this is a sensible change all in all, and one which should be done.
>
> My major gripe with it is the fact that you cannot pattern match on the
> stack trace. I see why this is done, but it feels like being a special
> arbitrary rule which goes against other matching patterns in the language.
> I'm not sure how it would help
>
> catch
>    Cl:Err:Stk ->
>         case {Cl, Err, Stk} of
>           ...
> end
>
> What I really like about the change is that it removes get_stacktrace/0
> which is a "bad function", and one of those things I tend to call a
> "language mistake" in Erlang[0].
>
> [0] For the interested, I think one of the most obvious mistakes are that a
> floating point numbers in Erlang cannot express NaNs and Infinities.
>
> On Fri, Nov 24, 2017 at 10:05 AM Björn Gustavsson <[hidden email]> wrote:
>>
>> There is a new EEP that proposes a new syntax in try/catch to retrieve
>> the stacktrace directly without using erlang:get_stacktrace/0:
>>
>> https://github.com/erlang/eep/blob/master/eeps/eep-0047.md
>>
>> /Björn
>> --
>> Björn Gustavsson, Erlang/OTP, Ericsson AB
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
>
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
>
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: EEP 47: Syntax in try/catch to retrieve the stacktrace directly

Björn Gustavsson-4
In reply to this post by Jesper Louis Andersen-2
On Sat, Nov 25, 2017 at 3:17 PM, Jesper Louis Andersen
<[hidden email]> wrote:
[...]
>
> My major gripe with it is the fact that you cannot pattern match on the
> stack trace.

Yes, I don't like that inconsistency myself, but I
think that the alternatives are worse.

If we were to implement pattern matching on the
stacktrace, it would be much slower than the
matching the pattern for the exception. I find
that kind of performance trap to be worse
than not allowing matching in the first place.

I have updated the pull request so that there
is now a compilation error if the variable for
the stacktrace is already bound. The compiler
already gives an error if an attempt is made
to use the stacktrace variable in the guard.

Since the compiler is that strict, it would be
a compatible change to implement matching
in the future, if it turns out that is desirable
or reduces user confusion.

/Björn

--
Björn Gustavsson, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: EEP 47: Syntax in try/catch to retrieve the stacktrace directly

Björn Gustavsson-4
In reply to this post by Richard Carlsson-3
On Mon, Nov 27, 2017 at 9:41 AM, Richard Carlsson
<[hidden email]> wrote:
> I agree that this is a good change. I can't even recall exactly why we went
> with the get_stacktrace() BIF - particularly since the value is already
> present as a variable under the hood. But I guess it was precisely to avoid
> such discussions about pattern matching on stack traces or having arbitrary
> restrictions such as "may only be a variable" on a part of a pattern. But I
> think such a restriction makes sense.

I have a vague memory that it was also problems with the parser. I had
to to refactor the yecc rules a bit to get it to work.

/Björn

--
Björn Gustavsson, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: EEP 47: Syntax in try/catch to retrieve the stacktrace directly

Jesper Louis Andersen-2
In reply to this post by Björn Gustavsson-4
On Mon, Nov 27, 2017 at 3:22 PM Björn Gustavsson <[hidden email]> wrote:
On Sat, Nov 25, 2017 at 3:17 PM, Jesper Louis Andersen
<[hidden email]> wrote:
[...]
>
> My major gripe with it is the fact that you cannot pattern match on the
> stack trace.

Yes, I don't like that inconsistency myself, but I
think that the alternatives are worse.

 
Yes, I think so too. In a typed language, you would probably declare an abstract type for the stack and not provide any kind of matching pattern for it. This would force people to handle the stack by printing, and there would be no matching on it at all.

Mimicking this behavior in Erlang is probably the sane behavior in this case.

I also like Richard's point: matching on the stack will eventually get you into trouble.

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: EEP 47: Syntax in try/catch to retrieve the stacktrace directly

Attila Rajmund Nohl
2017-11-27 15:31 GMT+01:00 Jesper Louis Andersen
<[hidden email]>:

> On Mon, Nov 27, 2017 at 3:22 PM Björn Gustavsson <[hidden email]> wrote:
>>
>> On Sat, Nov 25, 2017 at 3:17 PM, Jesper Louis Andersen
>> <[hidden email]> wrote:
>> [...]
>> >
>> > My major gripe with it is the fact that you cannot pattern match on the
>> > stack trace.
>>
>> Yes, I don't like that inconsistency myself, but I
>> think that the alternatives are worse.
>>
>
> Yes, I think so too. In a typed language, you would probably declare an
> abstract type for the stack and not provide any kind of matching pattern for
> it. This would force people to handle the stack by printing, and there would
> be no matching on it at all.
>
> Mimicking this behavior in Erlang is probably the sane behavior in this
> case.

If the stack trace is strictly for human consumption, why not return a
string (list or binary)?
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: EEP 47: Syntax in try/catch to retrieve the stacktrace directly

Richard Carlsson-3
In reply to this post by Jesper Louis Andersen-2
A discussion at work prompted me to think a bit more about this, so I thought I should share the following reasoning for posterity:

First, as a general principle we don't want patterns to carry a surprising cost, especially in the case they don't match. For example, it's possible to match on "abc"++Rest, but not on Prefix++"abc" or Prefix++"abc"++Rest, since that would imply a linear search through an arbitrary-length string. The same goes for binary patterns: you can't have a field of unknown length, except when it's the whole remainder of the binary.

For exceptions, the cost of building the symbolic form of the stack trace lies in 1) allocating and filling in list cells and tuples on the heap, and 2) traversing tables to map the program pointers on the actual stack to find the corresponding source file and line number. This is definitely non-negligible. When an exception happens, only the raw pointers from the topmost N stack frames are saved, which is pretty cheap, but if someone wants to look at this, they will need to get the symbolic form that get_stacktrace() returns (and which will in the future be available in the optional Trace variable of the exception pattern). If an exception happens but nobody looks at the stack trace information, only a single small binary is created and becomes garbage again.

The problem is not when the pattern matches, and you catch the exception. In that case you were probably willing to take the performance hit anyway, if you were matching on stack trace info. The problem is when someone introduces a seemingly innocent try...catch...end that is rarely expected to actually match, in a control flow where exceptions do happen a lot as part of the general execution - perhaps using throw for nonlocal returns out of deep recursion. If you have code like this, being called a lot, perhaps in a tight loop:

    find(Key) ->
        try search(Key)
        catch
            throw:aborted -> []
        end.

that seems perfectly fine, right? Just a wrapper.  Maybe you use it in a call to flatmap() and you want empty lists instead of exceptions when nothing is  found. But now someone else tweaks the search() function (or you have made the search function a parameter, and someone passes a new fun) so that it does the following:

    search(Key) ->
        try
            ...  % main body of search
        catch
            _Class:_Term:[{foobar,f,2,_} | _] -> []
        end.

This is also straightforward looking. Just a monkey-patch to fix a known error case returning an empty list instead. Expected to occur very rarely.

But what happens now, is that every time the called code throws 'aborted' - which might be often - the inner try/catch will be expanding the exception to its symbolic form, so that you can check whether it comes from a particular module/function. Even if this never actually matches, you will take the penalty of traversing the tables and allocating data on the heap. When the check has been made and the clause didn't match, the exception will be re-thrown to the outer try/catch which handles it instead as expected. The only observed difference is suddenly increased cpu usage and garbage creation.

We (famously) had a bug in our code some years back that made the system very unstable, garbage collecting a lot and being generally unresponsive. It was hard to diagnose, but it was just because of this anti-pattern, albeit implemented by calling get_stacktrace, ignoring the result and then rethrowing the exception explicitly. Making it even easier to accidentally cause this sort of problems by writing a simple little pattern in a catch-clause would be a worse thing than artificially restricting the expressiveness of catch-patterns.

That's why the Trace pattern should only be allowed to be an unbound variable.

        /Richard

2017-11-27 15:31 GMT+01:00 Jesper Louis Andersen <[hidden email]>:
On Mon, Nov 27, 2017 at 3:22 PM Björn Gustavsson <[hidden email]> wrote:
On Sat, Nov 25, 2017 at 3:17 PM, Jesper Louis Andersen
<[hidden email]> wrote:
[...]
>
> My major gripe with it is the fact that you cannot pattern match on the
> stack trace.

Yes, I don't like that inconsistency myself, but I
think that the alternatives are worse.

 
Yes, I think so too. In a typed language, you would probably declare an abstract type for the stack and not provide any kind of matching pattern for it. This would force people to handle the stack by printing, and there would be no matching on it at all.

Mimicking this behavior in Erlang is probably the sane behavior in this case.

I also like Richard's point: matching on the stack will eventually get you into trouble.

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions



_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions