Structs (was RE: Record selectors)

Joe Armstrong joe@REDACTED
Wed Jan 15 10:39:07 CET 2003


> Joe Armstrong <joe@REDACTED> wrote:
> 
> > [...]
> >   With structs you can write things like:
> > 
> > 	A = ~{name="joe", footSize=42},   %% define a struct
> > 	A.footSize,                       %% access a field
> > 	B = ~A{likes="motorbikes"},       %% add a new field
> > 	~{likes=X, name=N} = B}           %% pattern match etc.
> > 
> >   *without* any record defs.
> 
> Hm, OK, I've read the paper, let me see if I've got this straight.
> 
> Structs are basically dictionaries a la the dict module, except:
> 
> 1) you can pattern-match on their contents
> 2) they have their own special syntactic sugar
> 3) they're implemented directly in the VM for performance
> 
> Well, #1 is a great advantage over dicts, of course.
> 
> #2 is a mixed blessing - A.footSize is easier to read and to type out than
> dict:fetch(A, footSize), but it's also rather unorthogonal, symbolspace
> is getting more and more crowded, "~" is easy to confuse with "-" in many
> fonts, plus I personally think tildes are kind of ugly :)
> 

  The problem is more due to the dot than the tilde :-)

  . means 

	- end of a function or attribute
	- the separator in a floating point number
	- separator in a structured module name
        - record separator

  That's why you need a tilde or hash to help the parser (and the human)
  
	~ means here comes a struct
	# means here comes a record 

> #3 is arbitrary (there's no reason dicts or any other data type couldn't
> be implemented in the VM too.)
> 

  It's not really *arbitrary* - this  is one of the most tricky design
decisions there is.

  The  choices of  what you  do  in compact  syntax and  what you  do
efficiently in the VM are crucial.

  The "send" operation is written

	A ! B

  And compiles down to a single Op  code in the VM - also a great deal
of effort  has gone into  the implementation of  send. This is  not an
arbitrary decision but something that is at the very heart of language
design.

  If the user had to write.

	send_message(A, B)

  And if the *implementation* of send  was slow - then Erlang would be
useless as a concurrent PL.

  Language design *is* (in a sense) choosing which operations should be
expressed by succinct syntax and efficiently implemented.

> Also, since it's one of the considerations that sparked this thread, it's
> worth noting that structs are in no way safer that records; in fact,
> they're so flexible that they're arguably less safe.  Records have
> rigid structure, while structs, like dicts, are just random bags of data.

  Yes   -  but  structs   do  fit   nicely  with   the  rest   of  the
language. Records do  not have the Erlang "feel" -  they are too rigid
for my liking - and the mess with include files is very non-Erlang.

  You will introduce  new errors by typos in  struct member names, but
this is no  worse than mis-spelling an atom in  any other context, and
while mis-spelt atom names *is* a problem it is not a *big* problem.

  I routinely run  all my code through "coverage" -  and this picks up
virtually  all errors  due to  mis-spelt atom  names. <aside>everybody
should do this</aside>


> So, I don't want to sound too negative, but honestly, I'm less than
> thrilled by the idea.
> 
> But, that's possibly because the world I live and program in puts an
> emphasis on validation.  I still think you can get more "bang for your
> buck" with "objects" - if you write a module for each data type you use,
> you have full control over the interface, you can screen out bad data
> before it gets into the aggregate, you can use whatever storage scheme you
> like (and change it at a later date,) you have a convenient place to group
> all the applicable functions, etc etc, at a base cost surely not *too*
> much greater than using structs...

  My view is that data validation *only* occurs at a human -> computer
interface and  at a boundary  where two components communicate  via. a
protocol and where the components are not trusted.  For this something
like my UBF  system http://www.sics.se/~joe/ubf seems to be  a step in
the right  direction. UBF  + timing +  (other non functional  stuff) +
invariants would seem to be the right way to go.

  Basically you  validate data  (as hard you  can) when it  enters the
system.  Thereafter,  and internally there  should be no  validation -
just  let things  crash  and  design the  error  recovery through  the
application of carefully chosen invariants.

> 
> Forgive me, but is Erlang really so object-shy that encapsulation is
> something that we feel we can afford to avoid simply because "they" have
> turned it into a meaningless buzzword?
> 

  No encapsulation is fine - but objects (as in OO languages) do a lot
more than just encapsulate things.

/Joe



> -Chris
> 




More information about the erlang-questions mailing list