[m-rev.] for review: finalisers and exceptions

Julien Fischer juliensf at csse.unimelb.edu.au
Fri Feb 9 19:15:55 AEDT 2007


Estimated hours taken: 1
Branches: main

Specify the behaviour of finalisers and mutable initial value expressions
w.r.t to exceptions.

doc/reference_manual.texi:
 	Specify what happens if a finaliser terminates with an uncaught
 	exception.

 	Specify the order of initialisation for mutables w.r.t initialise
 	declarations.

 	Specify what happens if a mutable initial value expression
 	terminates with an uncaught exception.

tests/hard_coded/Mmakefile:
 	Add the new test cases.

tests/hard_coded/final_excp.{m,exp}:
 	Test the behaviour of finalisers that throw exceptions.

test/hard_coded/mutable_init_order.{m,exp}:
 	Test that mutables are initialised in the correct order relative
 	to initialise declarations.

tests/hard_coded/mutabel_excp.{m,exp}:
 	Test the behaviour of mutable initial value expressions that
 	throw exceptions.

Julien.

Index: doc/reference_manual.texi
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/doc/reference_manual.texi,v
retrieving revision 1.381
diff -u -r1.381 reference_manual.texi
--- doc/reference_manual.texi	8 Feb 2007 01:08:10 -0000	1.381
+++ doc/reference_manual.texi	9 Feb 2007 08:12:06 -0000
@@ -4771,6 +4771,11 @@
  standard library will always occur after any finalisation predicates have been
  invoked.

+If @samp{finalpredname/arity} terminates with an uncaught exception then
+the program will immediately abort execution.  No predicates specified
+by other @samp{finalise} directives that have not yet been executed will
+be executed.
+
  @samp{finalize} is also allowed as a synonym for @samp{finalise}.

  Note: @samp{finalise} declarations are currently only supported on
@@ -4886,6 +4891,23 @@
  It is an error for a @samp{mutable} directive to appear in the
  interface section of a module.  The usual visibility rules for sub-modules
  apply to the mutable variable access predicates.
+
+For the purposes of determining when mutables are assigned their inital
+values, the expression @samp{inital_value} behaves as though it were
+a predicate specified in an @samp{initialise} directive.
+
+ at example
+        :- initialise foo/2.
+        :- mutable(bar, int, 561, ground, [untrailed]).
+        :- initialise baz/2.
+ at end example
+
+In the above example @samp{foo/2} is invoked first, then the initial
+value of @samp{bar} is set to 561 and then @samp{baz/2} is invoked.
+
+The effect of a mutable initial value expression terminating with
+an uncaught exception is also the same as though it were a predicate
+specified in a @samp{initialise} directive.

  Note: @samp{mutable} declarations are currently only supported on
  the C backends.
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.307
diff -u -r1.307 Mmakefile
--- tests/hard_coded/Mmakefile	8 Feb 2007 01:08:11 -0000	1.307
+++ tests/hard_coded/Mmakefile	9 Feb 2007 08:12:06 -0000
@@ -130,6 +130,7 @@
  	mode_choice \
  	multi_map_test \
  	multimode \
+	mutable_init_order \
  	myset_test \
  	name_mangling \
  	no_fully_strict \
@@ -431,8 +432,10 @@
  		allow_stubs \
  		backend_external \
  		dir_test \
+		final_excp \
  		init_excp \
  		map_merge_test \
+		mutable_excp \
  		io_globals_deadlock \
  		test_array2d \
  		test_injection \
@@ -614,10 +617,30 @@
  		rm -f $@.tmp; \
  	fi

+# final_excp.out is expected to fail (it calls throw/1).
+#
+final_excp.out: final_excp
+	if ./final_excp > $@.tmp 2>&1; then \
+		grep  . $@.tmp; \
+		exit 1; \
+	else \
+		mv $@.tmp $@; \
+	fi
+
  # init_excp.out is expected to fail (it calls throw/1).
  #
  init_excp.out: init_excp
  	if ./init_excp > $@.tmp 2>&1; then \
+		grep  . $@.tmp; \
+		exit 1; \
+	else \
+		mv $@.tmp $@; \
+	fi
+
+# mutable_excp.out is expected to fail (it calls throw/1).
+#
+mutable_excp.out: mutable_excp
+	if ./mutable_excp > $@.tmp 2>&1; then \
  		grep  . $@.tmp; \
  		exit 1; \
  	else \
Index: tests/hard_coded/final_excp.exp
===================================================================
RCS file: tests/hard_coded/final_excp.exp
diff -N tests/hard_coded/final_excp.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/final_excp.exp	9 Feb 2007 08:12:06 -0000
@@ -0,0 +1,4 @@
+This is final_pred_a/2
+EXCEPTION
+Uncaught Mercury exception:
+magic_number_exception
Index: tests/hard_coded/final_excp.m
===================================================================
RCS file: tests/hard_coded/final_excp.m
diff -N tests/hard_coded/final_excp.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/final_excp.m	9 Feb 2007 08:12:06 -0000
@@ -0,0 +1,63 @@
+% Check that finalisers that terminate with an uncaught exception
+% cause the program to abort rather than keep running (i.e. execute
+% other finalisers).
+:- module final_excp.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module exception.
+
+:- finalise final_pred_a/2.	% Should be called first and succeed.
+:- finalise final_pred_b/2.	% Should be called second and abort. 
+:- finalise final_pred_c/2. 	% Should *not* be called.
+
+main(!IO).
+
+:- pred final_pred_a(io::di, io::uo) is cc_multi.
+
+final_pred_a(!IO) :-
+	io.write_string("This is final_pred_a/2\n", !IO),
+	try(get_string(561), Result),
+	(
+		Result = succeeded(_),
+		io.write_string("SUCCEEDED\n", !IO)
+	;
+		Result = exception(_),
+		io.write_string("EXCEPTION\n", !IO)
+	),
+	io.flush_output(!IO).
+
+:- pred final_pred_b(io::di, io::uo) is det.
+
+final_pred_b(!IO) :- 
+	get_magic_number(X, !IO),
+	( X = 3 ->
+		throw(magic_number_exception)
+	;
+		io.write_string("This is final_pred_b/2\n", !IO)
+	).
+
+:- pred final_pred_c(io::di, io::uo) is det.
+
+final_pred_c(!IO) :-
+	io.write_string("final_pred_c/2: I should not be running.\n", !IO).
+
+:- type magic_number_exception ---> magic_number_exception.
+
+:- pred get_string(int::in, string::out) is det.
+
+get_string(X, Str) :-
+	( X = 561 ->
+		throw(magic_number_exception)
+	;
+		Str = "not 561"
+	). 
+
+:- pred get_magic_number(int::out, io::di, io::uo) is det.
+
+get_magic_number(3, !IO).
Index: tests/hard_coded/mutable_excp.exp
===================================================================
RCS file: tests/hard_coded/mutable_excp.exp
diff -N tests/hard_coded/mutable_excp.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/mutable_excp.exp	9 Feb 2007 08:12:06 -0000
@@ -0,0 +1,3 @@
+init_foo: X = 40
+Uncaught Mercury exception:
+magic_number_exception
Index: tests/hard_coded/mutable_excp.m
===================================================================
RCS file: tests/hard_coded/mutable_excp.m
diff -N tests/hard_coded/mutable_excp.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/mutable_excp.m	9 Feb 2007 08:12:06 -0000
@@ -0,0 +1,70 @@
+% Test mutables whose inital value expressions throw exceptions.
+% 
+:- module mutable_excp.
+:- interface.
+
+:- import_module io.
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module exception. 
+
+:- mutable(foo, int, init_foo, ground, [untrailed, attach_to_io_state]).
+:- mutable(bar, int, init_bar, ground, [untrailed, attach_to_io_state]).
+:- mutable(baz, int, init_baz, ground, [untrailed, attach_to_io_state]).
+
+:- func init_foo = int.
+
+init_foo = X :-
+	promise_equivalent_solutions [X] (
+		try(get_string(561), Result),
+		(
+			Result = succeeded(_),
+			X = 80
+		;
+			Result = exception(_),
+			X = 40
+		),
+		trace [io(!IO)] (
+			io.write_string("init_foo: X = ", !IO),
+			io.write_int(X, !IO),
+			io.nl(!IO),
+			io.flush_output(!IO)
+		)
+	).
+
+:- func init_bar = int.
+
+init_bar = 
+	( get_magic_number(3) ->
+		throw(magic_number_exception)
+	;
+		561
+	).
+
+:- func init_baz = int.
+
+init_baz = X :-
+	trace [io(!IO)] (
+	    io.write_string("init_baz: I should not be running.\n", !IO)
+	),
+	X = 10.
+
+:- pred get_string(int::in, string::out) is det.
+
+get_string(X, Str) :-
+	( X = 561 ->
+		throw(magic_number_exception)
+	;
+		Str = "not 561"
+	). 
+
+:- type magic_number_exception ---> magic_number_exception.
+
+:- pred get_magic_number(int::out) is det.
+
+get_magic_number(3).
+
+main(!IO) :-
+	io.write_string("main: I should not be running.\n", !IO).
Index: tests/hard_coded/mutable_init_order.exp
===================================================================
RCS file: tests/hard_coded/mutable_init_order.exp
diff -N tests/hard_coded/mutable_init_order.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/mutable_init_order.exp	9 Feb 2007 08:12:06 -0000
@@ -0,0 +1 @@
+V = 908
Index: tests/hard_coded/mutable_init_order.m
===================================================================
RCS file: tests/hard_coded/mutable_init_order.m
diff -N tests/hard_coded/mutable_init_order.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/mutable_init_order.m	9 Feb 2007 08:12:06 -0000
@@ -0,0 +1,24 @@
+% Test that mutable initialisation occurs in the correct order
+% relative to initialise declarations.
+%
+:- module mutable_init_order.
+:- interface.
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- mutable(global, int, 561, ground, [untrailed, attach_to_io_state]).
+:- initialise foo/2.
+
+:- pred foo(io::di, io::uo) is det.
+
+foo(!IO) :-
+	set_global(908, !IO).
+
+main(!IO) :-
+	get_global(V, !IO),
+	io.write_string("V = ", !IO),
+	io.write_int(V, !IO),
+	io.nl(!IO).

--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list