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