[erlang-questions] predefined Erlang version macros

Fred Hebert mononcqc@REDACTED
Tue Jul 2 15:53:50 CEST 2013


A lot of people ask for this, but the problem is that 'R15' or 'R16B'
and so on are release names. This means that if I package my own Erlang
release with a subset (or superset) of OTP applications shipped with
R16B01, I can give it a new name and the macros will start breaking.

This includes the potential (but yet to be seen) use case of making a
release that uses libraries from two (or more) distinct OTP releases at
once.

Instead, what you should do is find a way to do feature-detection: load
the application at compile-time, find the version it has, and do some
optional branching based on that. It's much more complex, but it uses an
application-based mechanism instead of trying to rely on the release
name, which is not fixed.

Here's an example that could be done with a parse-transform. For the
user of the code:

    -module(some).
    -export([main/0]).
    -compile({parse_transform, ssh_behaviour}).
    
    %% R16B: use new ssh behaviour
    -behavior(ssh_daemon_channel).
    %% R15: use old ssh behaviour
    -behaviour(ssh_channel).
    
    main() -> ok.

And the parse transform that verifies whether 'ssh_daemon_channel'
exists or not to pick what to include:

    -module(ssh_behaviour).
    -export([parse_transform/2]).
    
    parse_transform(Forms, _Options) ->
        lists:filter(fun pred/1, Forms).
    
    pred({attribute, _Ln, behaviour, ssh_daemon_channel}) ->
        %% always include when available
        is_available(ssh_daemon_channel);
    pred({attribute, _Ln, behaviour, ssh_channel}) ->
        %% only include when ssh_daemon_channel is not available
        not is_available(ssh_daemon_channel);
    %% Same predicates but for americans
    pred({attribute, _Ln, behavior, ssh_daemon_channel}) ->
        is_available(ssh_daemon_channel);
    pred({attribute, _Ln, behavior, ssh_channel}) ->
        not is_available(ssh_daemon_channel);
    %% Skip the rest
    pred(_Form) ->
        true.
    
    is_available(Mod) ->
        try
            %% if the module loads, it means it exists
            _ = Mod:module_info(),
            true
        catch error:undef -> % doesn't exist
            false
        end.

Now the code can be shorter if you only want to support 'behavior' or
'behaviour', but this macro will make sure only one of the two modules
will be used for the behaviour, at compile time, based on the
assumptions that you will compile and run code with the same version,
and that you do not compile with the VM in embedded mode (which forbids
loading modules dynamically). This one should work for all releases
without a problem, given it works by doing feature detection rather than
trying to find out about a name.

I just wish it were easier to do something like this than needing to
write custom macros.

Regards,
Fred.

On 07/02, Stefan Jahn wrote:
> Dear Erlang'ers,
> 
> sometimes it would be nice to enable version-dependend code such as
> needed here:
> 
>   %% R16B: use new ssh behaviour
>   %-behaviour(ssh_daemon_channel).
> 
>   %% R15: use old ssh behaviour
>   -behaviour(ssh_channel).
> 
> 
> Is there anything suitable in Erlang?  Or is it unwanted because of
> strict versioning requirements of modules and applications?
> 
> Thank you in advance,
>   Stefan.
> 
> 
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions



More information about the erlang-questions mailing list