Remove behaviour checking from erl_lint (continued)

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

Remove behaviour checking from erl_lint (continued)

Michael Truog
Based on the discussion of https://github.com/erlang/otp/pull/1274 there
needs to be a discussion on the mailing list to determine if we can
remove behaviour checking in the Erlang compiler, and to determine where
the behaviour checking will be done in the future.

Since the atomic update unit for source code in Erlang is a module, not
an Erlang/OTP application, it seems best (to me) to avoid having the
compiler attempt to process Erlang/OTP applications, unless many things
were changed so that all Erlang/OTP application modules were versioned
and updated together, possibly allowing the coexistence of separate
versions of the same Erlang/OTP application.  Inlining across module
boundaries has been discussed before (e.g.,
http://erlang.org/pipermail/erlang-questions/2015-December/086943.html 
https://github.com/erlang/otp/pull/1274 ), and pursuing inlining within
an Erlang/OTP application seems best if the Erlang/OTP application is
updated as one atomic update unit that is versioned together.

The current Erlang behaviour checking is a simpler problem that is
mainly about trying to determine where linting should take place. Much
of the lint activity for Erlang source code occurs in dialyzer, so that
seems like a natural place to move behaviour checking to (to me).  The
reason we are talking about this is to make sure the Erlang compiler is
a dependable executable that can be part of a dependable toolchain,
since we want a software stack that can work together in a way where
everything is as reusable as possible.  A compiler that sometimes fails
due to a warning when ran with parallel execution would be undependable
as part of a larger toolchain.  Having a toolchain that avoids
monolithic development helps to pursue more efficient development, since
each monolithic development effort is effectively a dead-end due to the
replicated effort in each monolithic result (similar to rebar2 and
rebar3 coexisting, and both being difficult to use in a separate
build-system).  Having several smaller tools that are reusable helps to
make sure everything can grow to fit any use-case (similar to how maven
has grown in the Java ecosystem).  So, this may not fit into one email
thread, but it does appear to require more discussion to move further.

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

Re: Remove behaviour checking from erl_lint (continued)

Gleb Vinogradov
Let's compare `-spec` and `-behaviour` declarations.
Erlang compiler doesn't check `-spec` declarations and doesn't produce warnings if function called with wrong parameters. Dialyzer does.
So, I think behaviour checks could be removed from compiler as well, and should be placed in dialyzer. So behaviours of compiler and dialyzer will be consistent - one tool compiles the code and doesn't care about declarations, but another does.

Best Regards,
Gleb

2016-12-20 4:52 GMT+07:00 Michael Truog <[hidden email]>:
Based on the discussion of https://github.com/erlang/otp/pull/1274 there needs to be a discussion on the mailing list to determine if we can remove behaviour checking in the Erlang compiler, and to determine where the behaviour checking will be done in the future.

Since the atomic update unit for source code in Erlang is a module, not an Erlang/OTP application, it seems best (to me) to avoid having the compiler attempt to process Erlang/OTP applications, unless many things were changed so that all Erlang/OTP application modules were versioned and updated together, possibly allowing the coexistence of separate versions of the same Erlang/OTP application.  Inlining across module boundaries has been discussed before (e.g., http://erlang.org/pipermail/erlang-questions/2015-December/086943.html https://github.com/erlang/otp/pull/1274 ), and pursuing inlining within an Erlang/OTP application seems best if the Erlang/OTP application is updated as one atomic update unit that is versioned together.

The current Erlang behaviour checking is a simpler problem that is mainly about trying to determine where linting should take place. Much of the lint activity for Erlang source code occurs in dialyzer, so that seems like a natural place to move behaviour checking to (to me).  The reason we are talking about this is to make sure the Erlang compiler is a dependable executable that can be part of a dependable toolchain, since we want a software stack that can work together in a way where everything is as reusable as possible.  A compiler that sometimes fails due to a warning when ran with parallel execution would be undependable as part of a larger toolchain.  Having a toolchain that avoids monolithic development helps to pursue more efficient development, since each monolithic development effort is effectively a dead-end due to the replicated effort in each monolithic result (similar to rebar2 and rebar3 coexisting, and both being difficult to use in a separate build-system).  Having several smaller tools that are reusable helps to make sure everything can grow to fit any use-case (similar to how maven has grown in the Java ecosystem).  So, this may not fit into one email thread, but it does appear to require more discussion to move further.

Best Regards,
Michael
_______________________________________________
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: Remove behaviour checking from erl_lint (continued)

Michael Truog
In reply to this post by Michael Truog
On 12/19/2016 11:09 PM, Michał Muskała wrote:
> Right now when I don't implement a callback I get the feedback from the compiler in a matter of seconds - the compiler is very quick even on large projects since it can be incremental. Moving the check to dialyzer will mean I need to launch a separate program and wait for its output, potentially couple minutes. This doesn't sound like an improvement to me.
>
> Michał.
>
It may not seem like an improvement, but it is required due to the compiler needing to focus only on the module it is trying to compile.  Any error checking that involves other modules needs to rely on something else, with dialyzer being the Erlang linting tool due to the dynamic typing in Erlang.  With static typing in C/C++ the linting can happen along with compilation.  Even if Erlang changes to process Erlang/OTP applications as chunks of modules, that doesn't handle when behaviours would be in other Erlang/OTP applications (also, that processing appears to only exist far in the future or just simply as a discussion topic, nothing concrete to talk/think about right now).

Your main complaint is the speed of execution of dialyzer, and that is another valid problem.  An easy way to try to fix the slowness in dialyzer is try to make it do less, where enabling more checks requires more flags.  The slowness perceived in dialyzer appears to be the main reason given for manual usage of xref, so there are also people that would prefer using xref instead, just simply due to it doing less and executing quicker when doing less.  My main concern is just being able to have a dependable toolchain for Erlang usage, so creating a new lint tool doesn't seem like a bad option for me.  Worst case is that it would only do behaviour checking, and could grow to whatever is required that dialyzer doesn't need to cover (just easy checks that doesn't require dialyzer's use of memory or execution time). That approach probably wants something more like xref.  However, xref seems to provide a long list of false negatives when it is used and it has tons of options to make
it used in countless ways, not making it a simple tool that everyone wants to use for all their development.

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

Re: Remove behaviour checking from erl_lint (continued)

Loïc Hoguin-3
On 12/20/2016 09:36 AM, Michael Truog wrote:

> On 12/19/2016 11:09 PM, Michał Muskała wrote:
>> Right now when I don't implement a callback I get the feedback from
>> the compiler in a matter of seconds - the compiler is very quick even
>> on large projects since it can be incremental. Moving the check to
>> dialyzer will mean I need to launch a separate program and wait for
>> its output, potentially couple minutes. This doesn't sound like an
>> improvement to me.
>>
>> Michał.
>>
> It may not seem like an improvement, but it is required due to the
> compiler needing to focus only on the module it is trying to compile.
> Any error checking that involves other modules needs to rely on
> something else, with dialyzer being the Erlang linting tool due to the

I believe Dialyzer already checks this, perhaps not exactly the same
way, and with missing behavior modules not being considered errors.

> Your main complaint is the speed of execution of dialyzer, and that is
> another valid problem.  An easy way to try to fix the slowness in
> dialyzer is try to make it do less, where enabling more checks requires
> more flags.  The slowness perceived in dialyzer appears to be the main
> reason given for manual usage of xref, so there are also people that
> would prefer using xref instead, just simply due to it doing less and
> executing quicker when doing less.  My main concern is just being able
> to have a dependable toolchain for Erlang usage, so creating a new lint
> tool doesn't seem like a bad option for me.  Worst case is that it would
> only do behaviour checking, and could grow to whatever is required that
> dialyzer doesn't need to cover (just easy checks that doesn't require
> dialyzer's use of memory or execution time). That approach probably
> wants something more like xref.  However, xref seems to provide a long
> list of false negatives when it is used and it has tons of options to
> make it used in countless ways, not making it a simple tool that
> everyone wants to use for all their development.

I'm not sure what you mean. It's not hard to run xref once with warnings
that provide no false positives, and if necessary have a more
informative run with possible false positives. Both runs will be largely
faster than Dialyzer (maybe not that much on trivial projects when the
PLT is already built, but definitely on projects with many modules, or
huge generated modules and so on).

I believe xref should be made more approachable though, either in
documentation or interface. It seems to be capable of a lot more than
"rebar xref".

Cheers,

--
Loïc Hoguin
https://ninenines.eu
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Remove behaviour checking from erl_lint (continued)

Fred Hebert-2
I'm not taking position here; I do enjoy the compiler yelling at me for
valid reasons when it can, and most tools out there provide good
integration with my editor based on its output rather than the output of
other tools.

That being said, I'm not closed to the idea of people who care about the
compiler's well-being to be able to clean it up and maintain it better.

On 12/20, Loïc Hoguin wrote:
>I believe xref should be made more approachable though, either in
>documentation or interface. It seems to be capable of a lot more than
>"rebar xref".
>

Xref is a better candidate to move that stuff to than dialyzer, which
requires minutes of runtime the first time around, but also requires a
lot of memory.

On my VPS, if I try to run dialyzer on the rebar3 code base, it will
take minutes, yes, but will also hover between 1.0 and 1.5GB of RAM
usage while pegging 3-4 of the 4 CPUs at 100%, until it eventually gets
killed by the OS.

That's for 62 source files, and 29,000 LoC (we get 59 files and 12637
lines of code if we stop analyzing certifi, which has CA cert bundles
inlined -- but does not change the overall dialyzer behaviour of getting
killed by the OS).

I'm not saying this to disparage dialyzer, but the type of analysis it
can do and that I use it for (and where I run it) does not include the
basic checks that xref or the compiler does.

xref usability also needs to be a bit better before I'd consider it to
be an intuitive tool that does not require wrapping before running as an
end user.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Remove behaviour checking from erl_lint (continued)

Richard A. O'Keefe-2
In reply to this post by Michael Truog
Let me offer another perspective.

Once you add -type and -spec declarations to your Erlang code,
it becomes ASTONISHING that your code is not in fact type checked
by the compiler.

There is no other programming language that I use or have ever
used in which source code *with* type information isn't checked
by the normal compiler, to the extent that it *can* be checked
locally.

It is fatally easy to think that because you took care
to write -type and -spec and the compiler is silent that
your code is type correct, when it isn't.

Long term, we should not be shunting off ever more checking
from the compiler to the dialyzer; on the contrary, the
dialyzer as a separate tool should disappear.  There should
still be some compiler option to say how *much* checking is
to be done, but the default should be "I'll check everything
I can within the limits of what you've given me".

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

Re: Remove behaviour checking from erl_lint (continued)

Michael Truog
On 12/21/2016 04:13 PM, Richard A. O'Keefe wrote:

> Let me offer another perspective.
>
> Once you add -type and -spec declarations to your Erlang code,
> it becomes ASTONISHING that your code is not in fact type checked
> by the compiler.
>
> There is no other programming language that I use or have ever
> used in which source code *with* type information isn't checked
> by the normal compiler, to the extent that it *can* be checked
> locally.
>
> It is fatally easy to think that because you took care
> to write -type and -spec and the compiler is silent that
> your code is type correct, when it isn't.
>
> Long term, we should not be shunting off ever more checking
> from the compiler to the dialyzer; on the contrary, the
> dialyzer as a separate tool should disappear.  There should
> still be some compiler option to say how *much* checking is
> to be done, but the default should be "I'll check everything
> I can within the limits of what you've given me".
>
It doesn't seem like what you have said is as specific as it could be.  I agree it would be nice to have the compiler to type checking on the single module it is processing.  However, are you suggesting that the Erlang compiler that is fed a single module should know about all other modules that will be used along with it, at the same time, and effectively run dialyzer on the single module?  Since, if so, that should inherit the speed and memory problems dialyzer has, only they would be multiplied by the number of modules being processed due to the overhead involved.  That would be a way of avoiding the need for dialyzer though.

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

Re: Remove behaviour checking from erl_lint (continued)

Karlo Kuna
In reply to this post by Richard A. O'Keefe-2
my opinion, 

if intent is to simplify components in tool chain such as compiler -> xref -> dialyzer ..... or some variation
then i agree that compiler should not check for any external deps. 
But in that case there should be added some standard tool to run that tool chain, because users don't want to spend much time 
on configuring things like that, and it should be default practice to run that tool instead just compiler. And if you have some special
needs to skip some steps or just use single step, than you still have all this discreet tools available to use them as you want.
But for that Dialyzer in my opinion should be heavily optimized. 

in a sense i see need for clear separation of tasks and responsibilities but on other hand i want default use case to be as simple 
as possible and also as strict as possible.

On Thu, Dec 22, 2016 at 1:13 AM, Richard A. O'Keefe <[hidden email]> wrote:
Let me offer another perspective.

Once you add -type and -spec declarations to your Erlang code,
it becomes ASTONISHING that your code is not in fact type checked
by the compiler.

There is no other programming language that I use or have ever
used in which source code *with* type information isn't checked
by the normal compiler, to the extent that it *can* be checked
locally.

It is fatally easy to think that because you took care
to write -type and -spec and the compiler is silent that
your code is type correct, when it isn't.

Long term, we should not be shunting off ever more checking
from the compiler to the dialyzer; on the contrary, the
dialyzer as a separate tool should disappear.  There should
still be some compiler option to say how *much* checking is
to be done, but the default should be "I'll check everything
I can within the limits of what you've given me".


_______________________________________________
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: Remove behaviour checking from erl_lint (continued)

Richard A. O'Keefe-2
In reply to this post by Michael Truog


On 22/12/16 1:51 PM, Michael Truog wrote:

>> There is no other programming language that I use or have ever
>> used in which source code *with* type information isn't checked
>> by the normal compiler, to the extent that it *can* be checked
>> locally.

> It doesn't seem like what you have said is as specific as it could be.

It was a perspective, not a program!

> I agree it would be nice to have the compiler to type checking on the
> single module it is processing.  However, are you suggesting that the
> Erlang compiler that is fed a single module should know about all other
> modules that will be used along with it, at the same time, and
> effectively run dialyzer on the single module?

I was in fact specific about that:
"to the extent that it *can* be checked locally".
So no, I obviously *wasn't* suggesting that.

To be a bit more specific:
  - use the PLT to get information about library modules
  - assume that all calls to this module from outside
    are correct
  - assume that all calls from this module to outside
    code not described in the PLT are correct
  - check only that.
  - on request show a list of external functions called
    but not checked, mainly to avoid the illusion that
    everything was checked.

More generally, there should be a way to compile N modules
together, allowing calls between them to be checked but not
calls outside that group.

I find that the majority of my type errors are internal.

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

Re: Remove behaviour checking from erl_lint (continued)

Richard A. O'Keefe-2


On 22/12/16 2:02 PM, Richard A. O'Keefe wrote:
> I find that the majority of my type errors are internal.

There's a theory about why this is so:
  + when I call a library function, I look it up.
  - when I call module-internal functions, there
    might not be anything to look up yet.  In fact
    I might be writing the code *in order to find
    out* what the interface should be.

  + library interfaces are stable.
  - whenever I refactor module-internal code,
    there's a risk of an incomplete edit, so that
    code that *was* correct isn't any more.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions