Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specifications for functions: -spec. Efficiently usage

Tags:

erlang

How could I use -spec word in erlang? Please give me an idea of efficient usage of this word. Does is stands for documentation purposes only?

I'm try to apply a constraint to function in module by function type specification using -spec, but I've failed - no restrictions have been applied.

like image 318
egor7 Avatar asked Feb 21 '12 13:02

egor7


People also ask

What are two main measures for the efficiency of an algorithm?

The two main measures for the efficiency of an algorithm are time complexity and space complexity, but they cannot be compared directly. So, time and space complexity is considered for algorithmic efficiency. An algorithm must be analyzed to determine the resource usage of the algorithm.

How can we increase the efficiency of algorithm?

I have to swap numbers in an array 'd' times, so that left rotation of the array can be done. 'd' is the number of rotations of the array. Suppose if the array is 1->2->3->4->5 and if the d=1 then after one left rotation the array will be 2->3->4->5->1.

What are documentation requirements?

A requirements document defines what is needed from the product. It states the product's purpose and what it must achieve. It does not define how to deliver or build what is needed.


1 Answers

-spec attributes are indeed treated by the compiler and the runtime system as documentation. You cannot add any "executable features" to your code using them and the same applies for -type and -opaque attributes.

However they are useful as:

  • Documentation: they used by EDoc to generate all different forms of documentation for your code. -spec attributes are function signatures which, depending on how much effort you put into them, can make your code more understandable and maintainable. Suppose that your favorite data structure this month is dict(). Consider the following code:

    my_function(SomeArg, SomeOtherArg, Dict) ->
      ...
      dict:find(SomeKey, Dict)
      ...
    

    The variable that is being used as a dict has been named as such. But let's say that you have the following snippet:

    my_other_function(NamesDict, PlacesDict) ->
      ...
      R1 = my_function(A, B, NamesDict),
      ...
      R2 = my_function(C, D, PlacesDict),
    ...
    

    Trying to keep up with this might soon lead to code that repeats this Dict suffix. Even more, you might not even want to remember in the context of my_other_function that the two arguments are dict(). So instead you might want to do this:

    -spec my_other_function(dict(), dict()) -> atom().
    
    my_other_function(Names, Places) ->
      ...
      R1 = my_function(A, B, Names),
      ...
      R2 = my_function(C, D, Places),
      ...
    

    Now it is clear that these arguments should be dict() for the function to work and hopefully everyone will be able to figure that without going deep into the code. But suppose you are using this Name dict() in other places and it stores some particular information that is exposed with different APIs. Then it's a perfect candidate for a -type declaration:

    -type names() :: dict().
    
    -spec my_other_function(names(), places()) -> atom().
    
    my_other_function(Names, Places) ->
      ...
      R1 = my_function(A, B, Names),
      ...
      R2 = my_function(C, D, Places),
      ...
    

    If somebody else makes frequent use of this particular data structure you may want to export it too:

    -module(my_module).
    
    -export_type([names/0]).
    
    -type names() :: dict().
    

    Other modules can now refer to this particular data structure:

    -module(my_other_module).
    
    -record(my_state, {names :: my_module:names(),
                       ...}).
    

    Finally if you would prefer other developer to not inspect this data structure in any way in their modules, you can declare it as -opaque. Again, this is a "friendly suggestion", as is all the rest of the stuff so far. Or is it...?

  • Discrepancy detection: If you take time to use -specs and -types you would very much like that these are kept up to date. It is common knowledge that nobody maintains the documentation up to date if there is none watching! Luckily, Dialyzer is watching. Dialyzer can check that in all calls to my_function() the arguments are dict() (it can do this even without your -spec annotations but it's so easier if there are these there too) and scream bloody murder if you call it with something else. It can moreover keep track of these exported types and even report opacity violations. So it's not "just documentation".

  • Testcase generation: PropEr can use the -spec and -type definitions to automatically check your functions with random testcases. It is capable to make random testcases even from declarations like this one:

    -type int_tree() :: {node, integer(), tree(), tree()} | nil.
    
  • The brand new way to specify a set of callbacks for a behaviour is by using the familiar -spec syntax. Compiler, Dialyzer and possibly other tools can use this information to check a behaviours implementation. See more in the OTP behaviours code and here

Read more here.

like image 112
aronisstav Avatar answered Sep 30 '22 17:09

aronisstav