FW: [mercury-users] Records
Simon Taylor
stayl at cs.mu.OZ.AU
Wed Nov 3 15:29:29 AEDT 1999
Ralph Becket wrote:
> What I had in mind was something where I could declare an abstract type,
> but allow users of that type partial access to it via the record syntax.
> e.g. rather than writing
>
> :- interface.
> :- type foo.
> :- func get_field1(foo) = int.
> :- func set_field1(foo, int) = foo.
> :- func get_field2(foo) = string.
>
> :- implementation.
> :- type foo ---> foo(int, string, bool /* my extra field */).
> ...
>
> I was asking whether the record scheme would cover this sort of thing
> for me. In this case the user can copy foos and notionally access
> field1 (rw) and field2 (ro), but not get at the private state (the bool).
> This is similar to the private, public, final stuff in Java (which, btw,
> lacks a proper read-only declaration).
That hasn't been implemented yet, but would probably be useful. How about:
:- module foo3.
:- interface.
:- type t3
---> private t3(
const field1 :: int,
private field2 :: int
).
:- implementation.
The `private' annotation on constructor `t3' means that the constructor
cannot be used explicitly by modules importing `foo3'. Fields of the
constructor can only be extracted or modified using record syntax.
The `const' annotation on `field1' means that the field cannot be changed
using a field update expression.
The `private' annotation on `field2' means that the field extraction and
update expressions cannot be used outside module `foo3'.
One other idea I had was that one of the reasons for making a field private
is that there is an invariant on the field that must be checked on
each update. It would be a shame to have to use different syntax for
updating such fields. One way to fix that would be allow the user
to override the field update function.
:- module foo4.
:- interface.
:- type t4
---> t4(
% field1 must be positive.
field1 :: int where set is set_field1,
field2 :: int
).
:- func set_field1(t4, int) = t4.
:- implementation.
set_field1(Term0, Value) = 'builtin_set field1'(Term0, Value) :-
( Value < 0 ->
error("negative value for field1")
;
true
).
'builtin_set field1' is the usual expansion into unifications for
a field update expression (Term0 = t4(_, X2), Term = t4(Value, X2)).
'builtin_set field1' cannot be overridden by the programmer, and
cannot be called by modules importing module `foo4'.
> > zero_second_field_in_triple(X, X ^ second := 0).
> >
> > Actually I'm not sure if that's valid code under the new
> > record regime,
> > but it's something along those lines.
>
> I'd rather hope that would be valid code...
It is.
> I'm keen on having records with named fields in the language because
> I've worked on large projects (in Prolog) which had terrible problems
> whenever somebody added an extra field to a commonly used structure
> which was accessed by pattern matching rather than some more controlled
> interface. All sorts of things went wrong (and, it being Prolog, you
> didn't get to find out until run-time).
That kind of programmer will find ways to stuff things up no matter
how nice the language.
Simon.
--------------------------------------------------------------------------
mercury-users mailing list
post: mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the users
mailing list