[erlang-questions] Breaking backwards compatibility in Release 17.0-rc2

ANTHONY MOLINARO <>
Fri Feb 28 22:56:12 CET 2014


Yeah, looking at it, the -ifdef macro really only works with a single token, so you have to provide it externally, which is a bummer because it would have been really nice to do something like

-ifdef (?OTP_RELEASE > 15).
-callback...
-else.
-behaviour_info…
-endif.

Or

-ifdef (?OTP_RELEASE < 17).
-spec f(queue()) -> queue().
-else.
-spec f(queue:queue()) -> queue:queue().
-endif.

gcc has the pretty cool __GNUC_PREREQ (MAJOR, MINOR) macro which you can use certain features, but I have a feeling there would be opposition to make preprocessing do more stuff (plus even that macro appears to not help if you are compiling on say clang).

-Anthony

On Feb 28, 2014, at 1:09 AM, Loïc Hoguin <> wrote:

> A macro for ?OTP_RELEASE or ?OTP_VERSION makes *absolutely no sense*. There are no guarantees that people are going to compile on a fresh Erlang release. If I create a release named PONIES, this will not help at all when I then use the compiler app I included to compile some stuff at runtime.
> 
> Something a little better is ?COMPILER_VERSION, but people might also run a custom compiler code with a custom version number, so that's a no go either.
> 
> On 02/28/2014 09:36 AM, Vlad Dumitrescu wrote:
>> Hi,
>> 
>> I've been hit by this too, as I have a patched debugger that I need to
>> compile on older versions too and there are issues with
>> unicode/maps/named funs. Unfortunately, there might be cases where code
>> will still have to be duplicated, because macros can only wrap full forms.
>> 
>> From a brief look att epp.erl, it feels like adding a ?OTP_RELEASE or
>> ?OTP_VERSION predefined macro would be easy and the only possible
>> problem is if there are user-defined macros with the same name.
>> 
>> predef_macros(File) ->
>>      Machine = list_to_atom(erlang:system_info(machine)),
>>      {ok, Release0} = file:read_file(code:root_dir()++"/OTP_VERSION"),
>>      Release = string:strip(Release0, right, $\n),
>>      ...
>> {{atom,'OTP_RELEASE'},      {none,[{string,1,Release}]}},
>>      ...
>> 
>> By the way, wouldn't it be useful to have an erlang:system_info() that
>> reads the file and strips the 'ok' and the whitespace?
>> 
>> best regards,
>> Vlad
>> 
>> 
>> On Fri, Feb 28, 2014 at 1:08 AM, ANTHONY MOLINARO
>> < <mailto:>> wrote:
>> 
>>    I also have felt this pain with the transition from behaviour_info
>>    to callbacks for behaviours.  Ideally, the preprocessor would define
>>    a macro along the lines of ?MODULE, ?MODULE_STRING, ?FILE, ?LINE,
>>    and ?MACHINE which is the full list according to
>>    http://www.erlang.org/doc/reference_manual/macros.html.
>> 
>>    If there was one additional macro call ?RELEASE with the major
>>    release, then it would be possible to conditionally compile at least
>>    dialyzer stuff (I don't know about the file encoding, I guess it
>>    would depend on whether the check is done during the preprocessor or
>>    at a later step).  This would probably prevent the proliferation of
>>    different compile macros which seem to crop up as every individual
>>    library adds their own based on a rebar or makefile check.
>> 
>>    -Anthony
>> 
>>    On Feb 27, 2014, at 3:06 PM, Jesper Louis Andersen
>>    <
>>    <mailto:>> wrote:
>> 
>>>    Release 17.0 brings two changes which prove to take some work
>>>    getting around.
>>> 
>>>    1. utf-8 is now the default encoding.
>>> 
>>>    This is a rather insignificant change. The source code which uses
>>>    latin1 can be fixed by one of three ways:
>>> 
>>>    * Tell the compiler the file is latin1. This won't work going
>>>    forward but works now.
>>>    * Change the file to utf-8. This won't work going backward a long
>>>    way. But it will work going backwards for a bit.
>>>    * Change the file to ASCII. This works both backward and forward
>>>    as long as we want.
>>> 
>>>    This is a benign problem. I have tried compiling some projects and
>>>    it turns out there are numerous repositories which needs fixing
>>>    now. But the fix is rather simple.
>>> 
>>>    2. Dialyzer dislikes queue(), dict(), ...
>>> 
>>>    Dialyzer now prefers using queue:queue() and the like. This is
>>>    *definitely* the right thing to support as it is much more
>>>    consistent with the rest of the system and doesn't treat certain
>>>    types as magically introduced types.
>>> 
>>>    -module(z).
>>> 
>>>    -export([f/1]).
>>> 
>>>    -spec f(queue:queue()) -> queue:queue().
>>>    f(Q) -> queue:in(3, Q).
>>> 
>>>    Which is nice, but this doesn't work on R16B03:
>>> 
>>>    z.erl:5: referring to built-in type queue as a remote type; please
>>>    take out the module name
>>>    z.erl:5: referring to built-in type queue as a remote type; please
>>>    take out the module name
>>> 
>>>    So here, I have no way of getting my source code to work with both
>>>    R16 and 17.0 easily. There is no transition period so-to-speak.
>>>    Many projects run with warnings-as-errors and they are in trouble:
>>> 
>>>    * They can't compile
>>>    * They can remove the warnings-as-errors but this defeats the purpose
>>>    * They will have warnings spewed out over the console all the time
>>> 
>>>    In the case of crypto:hash/2, we had somewhat the same situation.
>>>    Prominent projects like Yaws, and lesser projects like Emysql has
>>>    EPP macros in place as well as detection in order to figure out
>>>    what to do. Or you can disable the warnings in this case
>>>    specifically for this. But can I do the same with wrong type
>>>    specs? Also, this workaround is done in almost every project out
>>>    there, which is darn irritating.
>>> 
>>>    I don't know what we need to solve this. At one point, I would
>>>    really like to have a set of feature flags
>>> 
>>>    http://www.lispworks.com/documentation/HyperSpec/Body/v_featur.htm
>>>    , ZFS, ...
>>> 
>>>    where you have a way to compile-time scrutinize what your
>>>    environment supports. Another way to solve it is the variant Go
>>>    uses, namely "build constraints"
>>> 
>>>    http://golang.org/pkg/go/build/#pkg-overview
>>> 
>>>    which will mention under which circumstances to include a file as
>>>    a part of an application. This would allow for easy handling of
>>>    crypto:hash/2, but I do note it will fail on the dialyzer problem.
>>>    It looks like the only sane way to solve that is to allow both
>>>    queue() and queue:queue() as aliases for a major release and then
>>>    proceed to remove queue().
>>> 
>>>    Am I completely wrong here? I can accept languages evolve and that
>>>    Release 17 has maps which will be used and break a lot of software
>>>    for R16 quickly. But I also feel we should have some way of having
>>>    a process so there is a way to handle this gracefully going
>>>    forward. It is natural for libraries and languages to evolve and
>>>    break compatibility. Yet, it should be easy to handle for
>>>    programmers. There is much time wasted, which could be used better
>>>    were there a nice solution.
>>> 
>>>    Thoughts?
>>> 
>>>    --
>>>    J.
>>>    _______________________________________________
>>>    erlang-questions mailing list
>>>     <mailto:>
>>>    http://erlang.org/mailman/listinfo/erlang-questions
>> 
>> 
>>    _______________________________________________
>>    erlang-questions mailing list
>>     <mailto:>
>>    http://erlang.org/mailman/listinfo/erlang-questions
>> 
>> 
>> 
>> 
>> _______________________________________________
>> erlang-questions mailing list
>> 
>> http://erlang.org/mailman/listinfo/erlang-questions
>> 
> 
> -- 
> Loïc Hoguin
> http://ninenines.eu




More information about the erlang-questions mailing list