I'm trying to understand the meaning and purpose of ::binary() that exist in record definition but don't really understand it. Appreciate if anyone can help me to understand this.
Example : mod_offline.hrl
This is a type declaration. This is described in the "Type Information in Record Declarations" section.
The meaning is that the value of that record field is supposed to be a binary. Since Erlang is a weakly typed language, the compiler doesn't care about this, but there is a static type checker called Dialyzer, that tries to find places in the code that puts something other than a binary in that field, or expects the field to hold something other than a binary.
For a gentle introduction to type specs and Dialyzer, see the Type Specifications and Erlang chapter of Learn You Some Erlang.
Related
Does the concept of "arity" solve this problem?
I had a quick look at http://www.erlang.org/doc/man/global.html, but it mostly seems to involve node registration, not resolution by name for functions or atoms.
Does CosNaming (http://www.erlang.org/doc/man/CosNaming_NamingContext.html) deal with this?
If by "name mangling" you mean the concept from C++ then no I don't think they do.
There's no function overloading in Erlang or Elixir. (I tried to find a source to point you to but trust me--it's just not there.) Functions are picked by arity alone and the same function name with two different arities is two different functions. f/0 is different than f/1 which is different from f/2. As #zxq9 pointed out in the comments, due to this property there's no variable arity in Erlang or Elixir either although that can be simulated by passing lists as parameters.
This portion of the Erlang docs discusses how Erlang figures out which function to resolve to. While the mechanism underneath is the same for Elixir the syntax is different.
Records are compile time structures. The record_info and is_record recognise the compiled records and their structures. Is there a way to ask the VM what records have been defined that are available to the process? I am interested in getting the internal tuple representation for every record definition.
What I want to do is something like:
-record(car,{make=honda}).
get_record(Car) ->
%% Some magic here to end up having sth like
{car,{make,honda}} or even better #car{} indeed. %% when Car = 'car'
As you said records are only a compile time construct, so once compiled records are only tuples, this would suggest no available information is left during runtime, but since you mentioned those two functions I was curious and I checked how they worked.
According to this record_info/2 is a pseudo function made available only during compilation, so it doesn't need any run time information on records.
On the other hand the description of is_record(Term, RecordTag) states that this BIF (built-in function) only "returns true if Term is a tuple and its first element is RecordTag, false otherwise", so it is actually only checking the structure and first element of the tuple.
Based on this, I would guess that there is no record information made available during runtime. This thread confirms the unavailability of record_info/2 during runtime.
I have used Dynarec (https://github.com/dieswaytoofast/dynarec.git) successfully in a data mapping module for one of the apps I am currently working on. It is a parse transformer, though, not a run-time VM tool. It compiles information on each defined record, as well as information about the fields for each record. In my case, I use it to dynamically map incoming data to record data. This module may get you what you need. YMMV. Good luck.
As others have said records are purely compile time and there is no runtime information about records. Erlang just sees tuples. For example the record_info/2 pseudo functions are expanded to data at compile time, a list of atoms for fields argument and an integer for size.
I came across some code today that looked somewhat like this:
subroutine foo()
real blah
integer bar,k,i,j,ll
integer :: n_called=1
save integer
...
end
It seems like the intent here was probably save n_called, but is that even a valid statment to save all integers -- or is it implicitly declaring a variable named integer and saving it?
The second interpretation is correct. Fortran has many keywords, INTEGER being one of them, but it has no reserved words, which means that keywords can be used as identifiers, though this is usually a terrible idea (but nevertheless it carries on to C# where one can prefix a keyword with # and use it as an identifier, right?)
The SAVE statement, even if it was intended for n_called is superficial. Fortran automatically saves all variables that have initialisers and that's why the code probably works as intended.
integer :: n_called=1
Here n_called is automatically SAVE. This usually comes as a really bad surprise to C/C++ programmers forced to maintain/extend/create new Fortran code :)
I agree with your 2nd interpretation, that is, the statement save integer implicitly declares a variable called integer and gives it the save attribute. Fortran, of course, has no rule against using keywords as program entity names, though most sensible software developers do have such a rule.
If I try to compile your code snippet as you have presented it, my compiler (Intel Fortran) makes no complaint. If I insert implicit none at the right place it reports the error
This name does not have a type, and must have an explicit type. [INTEGER]
The other interpretation, that it gives the save attribute to all integer variables, seems at odds with the language standards and it's not a variation that I've ever come across.
I suspect that the syntax diagram for a plsql_block as given in the
Oracle® Database PL/SQL Language Reference for Relese 2 is wrong.
(For reference, here's the current link to that document)
The following piece of PL/SQL compiles fine:
declare
cursor
cursor_definition
is select * from dual;
variable_declaration number;
begin
null;
end;
The following statements are assumptions that I make based on the piece of PL/SQL above and based on Oracle's syntax diagram.
The declare section (above) consists of a cursor definition followed by a variable declaration (which in turn is an item declaration).
An item declaration can only be an element of an item list 1.
A cursor definition can only be an element of an item list 2.
An item list 2 can never be followed by an item list 1.
Now, the variable declaration following the cursor definition contradicts point 4. Therefore I conclude that the
syntax diagram is wrong.
Maybe I am overlooking something, in which case I'd be very grateful for pointing this out to me.
Please understand that a wrong syntax diagram per se is no big deal to me. But I am in the process of writing a PL/SQL parser
and the parser stumbles for the exact situation given with the example PL/SQL code. So, in order to improve the parser, I'd like
to have a more authorative sequence diagram.
I concur. The syntax diagrams explicitly state that a plsql_block is effectively item_list_2 preceded by an optional item_list_1.
Further, cursor definitions (with the is bit) can only occur in item_list_2 and variable declarations (with or without an =) are part of the item_declaration set and can therefore only be in item_list_1.
Those facts make your code sample incorrect so, if it manages to compile, then either:
the syntax diagrams are wrong; or
the compiler doesn't follow them to the letter; or
your looking at code that's covered by different syntax diagrams.
On that last bullet point, interestingly enough, the syntax diagrams for 11.1 are slightly different.
The declare section can be item_list_1 or item_list_2 or item_list_1 followed by item_list_2.
Where it gets interesting is that item_list_1 can have any number of item_declaration entries and this includes both variable_declaration and cursor_declaration.
In 11.1, a cursor_declaration can be either a declaration or a definition, based on the language elements in 11.2 (in other words, there is no cursor_definition type since the declaration allows both in the declaration).
So what you have is perfectly valid in 11.1 so the first thing I'd check is that you're actually running 11.2 where that successful compilation is taking place.
It's still possible of course that you're running 11.2 and the syntax diagrams are wrong, in which case you should complain bitterly to Oracle but I don't know what sort of a response you'll get from a company whose flagship database product can't tell the difference between an empty varchar and a NULL (a).
(a) I'll never pass up an opportunity to mention this and advance the cause of my beloved DB2 :-)
In real terms, what is the difference between a "string" and a "string option"?
Aside from minor sytnax issues, the only difference I have seen is that you can pass a "null" to string while a string option expects a "none".
I don't particularly like the answer I've typed up below, because I think the reader will either see it as 'preaching to the choir' or as 'some complex nonsense', but I've decided to post it anyway, in case it invites fruitful comment-discussion.
First off, it may be noteworthy to understand that
let x : string option = Some(null)
is a valid value, that indicates the presence (rather than absence) of a value (Some rather than None), but the value itself is null. (The meaning of such a value would depend on context.)
If you're looking for what I see as the 'right' mental model, it goes something like this...
The whole notion that "all reference types admit a 'null' value" is one of the biggest and most costly mistakes of .Net and the CLR. If the platform were resdesigned from scratch today, I think most folks agree that references would be non-nullable by default, and you would need an explicit mechanism to opt-in to null. As it stands today, there are hundreds, if not thousands of APIs that take e.g. "string foo" and do not want a null (e.g. would throw ArgumentNullException if you passed null). Clearly this is something better handled by a type system. Ideally, 'string' would mean 'non-null', and for the minority of APIs that do want null, you spell that out, e.g. "Nullable<string> foo" or "Option<string> foo" or whatever. So it's the existing .Net platform that's the 'oddball' here.
Many functional languages (such as ML, one of the main influences of F#) have known this forever, and so designed their type systems 'right', where if you want to admit a 'null' value, you use a generic type constructor to explicitly signal data that intentionally can have 'asbence of a value' as a legal value. In ML, this is done with the "'t option" type - 'option' is a fine, general-purpose solution to this issue. F#'s core is compatible (cross-compiles) with OCaml, an ML dialect, and thus F# inherits this type from its ML ancestry.
But F# also needs to integrate with the CLR, and in the CLR, all references can be null. F# attempts to walk a somewhat fine line, in that you can define new class types in F#, and for those types, F# will behave ML-like (and not easily admit null as a value):
type MyClass() = class end
let mc : MyClass = null // does not compile
however the same type defined in a C# assembly will admit null as a proper value in F#. (And F# still allows a back-door:
let mc : MyClass = Unchecked.defaultof<_> // mc is null
to effectively get around the normal F# type system and access the CLR directly.)
This is all starting to sound complicated, but basically the F# system lets you pretty much program lots of F# in the 'ML' style, where you never need to worry about null/NullReferenceExceptions, because the type system prevents you from doing the wrong things here. But F# has to integrate nicely with .Net, so all types that originate from non-F# code (like 'string') still admit null values, and so when programming with those types you still have to program as defensively as you normally do on the CLR. With regards to null, effectively F# provides a haven where it is easy to do 'programming without null, the way God intended', but at the same time interoperate with the rest of .Net.
I haven't really answered your question, but if you follow my logic, then you would not ask the question (or would unask it, a la Joshu's MU from "Godel, Escher, Bach").
I think you could reclassify this as a more general question
What is the difference between option random ref type and just a random ref type
The difference is with an option, you are providing an explicit empty value case. It's a declarative way of saying "I might not provide a value". A option of value None unambiguously represents a lack of a value.
Often times people use null to represent a lack of a value. Unfortunately this is ambiguous to the casual reader because it's unknown if null represents a valid value or the lack of a value. Option removes this ambiguity.