Please find attached a proposed small patch for the Unicon
translator.  The patch allows an initially method to cause
the construction of an object to fail, by explicitly failing
itself.

An example of how this could be useful could be an
email-address class, as follows :-

class EmailAddress(user, host)
   ... get/set methods etc

   method print()
      write(user, "@", host)
   end

   initially(a[])
      if *a = 1 then {
         # a[1] should be in form "user@host"; parse into
constituent parts
         a[1] ? {
            # fail if no @ symbol
            user := tab(upto('@')) | fail
            move(1)
            host := tab(0)
         }
      } else if *a = 2 then {
         # a[1] is user, a[2] is host, no parsing needed
         user := a[1]
         host := a[2]
      } else
         runerr(0, "Wrong number of params to EmailAddress
constructor")
end

The intention being to construct objects as follows :-

   x := EmailAddress("smith", "jones.com")
or
   y := EmailAddress("[EMAIL PROTECTED]")

and also in the single parameter case to be able to check
for an invalid address

   z := EmailAddress("not an address (no at symbol)") |
write("invalid address")

But at present the last construction call actually succeeds,
and leaves user, host set to &null.  The failure in the
initially method doesn't propagate up to the constructor.

This small patch changes the generated code slightly so that
explicit failure in the initially method does indeed cause
the constructor to fail.

Note that explicit failure is required; just dropping off
the end of the initially block does not cause the
construction to fail.  For this reason, it is very unlikely
that this patch would break any existing code.  Only if
there was already an explicit "fail" statement in an
initially method would behaviour change; without the patch
the construction would succeed, with the patch it would not.
Index: idol.icn
===================================================================
RCS file: /cvsroot/unicon/unicon/uni/unicon/idol.icn,v
retrieving revision 1.3
diff -u -r1.3 idol.icn
--- idol.icn    2001/12/02 09:47:25     1.3
+++ idol.icn    2002/01/21 19:00:51
@@ -442,17 +442,17 @@
                    move(1)   # if last was nonfinal write it
                    if find(",") then writes(f,",")
                    }
-                writes(f, "]|||", tab(0),")")
+                writes(f, "]|||", tab(0),") | fail")
                  }
              else {
-               write(f,"  self.__m.initially!(push(", tab(0), ",self))")
+               write(f,"  self.__m.initially!(push(", tab(0), ",self)) | fail")
                   }
             }
          }
       else {
           writes(f,"  self.__m.initially(self,")
           yyprint(m.fields)
-          yyprint(")\n")
+          yyprint(") | fail\n")
           }
        }
     else {
@@ -460,7 +460,7 @@
        if \self.ifields then every writes(f,",",(!self.ifields).ident)
        yyprint(")\n  self.__s := self\n")
     if ((methods$foreach())$name()| (!self.imethods).ident) == "initially" then
-         yyprint("  self.__m.initially(self)\n")
+         yyprint("  self.__m.initially(self) | fail\n")
        }
 
     #
@@ -583,6 +583,8 @@
        yyprint(initl)
        (\fields).coercions()
        yyprint(procbody)
+       if name=="initially" then
+          writes(f, "\n      return")
        }
     else write(f, "   runerr(700, \"method " || name || "()\")")
     yyprint("\nend\n")

Reply via email to