From 1e8ea9fd960644a14cbdddb4861000341fcd6bbb Mon Sep 17 00:00:00 2001 From: James Clark Date: Fri, 1 May 2020 16:52:45 +0700 Subject: [PATCH] Revised error type design Deals with most of #509. --- lang/lib/error.bal | 27 ++++++-------- lang/lib/value.bal | 2 +- lang/spec.html | 90 ++++++++++++++++++++-------------------------- 3 files changed, 50 insertions(+), 69 deletions(-) diff --git a/lang/lib/error.bal b/lang/lib/error.bal index de23efb9..00c1ea4b 100644 --- a/lang/lib/error.bal +++ b/lang/lib/error.bal @@ -15,14 +15,7 @@ // under the License. # The type to which error detail records must belong. -# -# + message - the error message -# + cause - the error cause -public type Detail record {| - string message?; - error cause?; - (anydata|readonly)...; -|}; +public type Detail map; # A type parameter that is a subtype of error `Detail` record type. # Has the special semantic that when used in a declaration @@ -30,23 +23,23 @@ public type Detail record {| @typeParam type DetailType Detail; -# A type parameter that is a subtype of `string` type. -# Has the special semantic that when used in a declaration -# all uses in the declaration must refer to same type. -@typeParam -type StringType string; +# Returns the error's message. +# +# + e - the error value +# + return - error message +public function message(error e) returns string = external; -# Returns the error's reason string. +# Returns the error's cause. # # + e - the error value -# + return - error reason -public function reason(error e) returns StringType = external; +# + return - error cause +public function cause(error e) returns error? = external; # Returns the error's detail record. # The returned value will be immutable. # + e - the error value # + return - error detail value -public function detail(error e) returns DetailType = external; +public function detail(error e) returns DetailType = external; # Returns an object representing the stack trace of the error. # diff --git a/lang/lib/value.bal b/lang/lib/value.bal index 83394bcb..ed7bc069 100644 --- a/lang/lib/value.bal +++ b/lang/lib/value.bal @@ -104,7 +104,7 @@ public function isReadOnly(anydata v) returns boolean = external; # - if `v` is an error, then a string consisting of the following in order # 1. the string `error` # 2. a space character -# 3. the reason string +# 3. the message string # 4. if the detail record is non-empty # 1. a space character # 2. the result of calling toString on the detail record diff --git a/lang/spec.html b/lang/spec.html index f1ce5ebd..b0314dc9 100644 --- a/lang/spec.html +++ b/lang/spec.html @@ -1632,65 +1632,42 @@

Behavioral values

-

Error

+

Errors

error-type-descriptor := error [error-type-params]
-error-type-params := < (explicit-error-type-params | inferred-error-type-param) >
-explicit-error-type-params := reason-type-descriptor [, detail-type-descriptor]
-reason-type-descriptor := type-descriptor
+class="grammar">error-type-descriptor := error [error-type-param]
+error-type-param := < (detail-type-descriptor | inferred-type-descriptor) >
 detail-type-descriptor := type-descriptor
-inferred-error-type-param := *
+inferred-type-descriptor := *
 

-An error value is used to represent an error. Errors are a distinct basic type: -a value belongs to the error basic type if and only if it is an error. This -means that errors are clearly distinguished from other values. Many constructs -in Ballerina give special treatment to error values. The error type is -inherently immutable. An error value contains the following information: +An error value provides information about an error that has occurred. Error +values belong to a separate basic type; this makes it possible for language +constructs to handle errors differently from other values. +

+

+The error type is inherently immutable. An error value contains the following +information:

    -
  • a reason, which is a string identifier for the category of error
  • +
  • a message, which is a string containing a human-readable message describing +the error
  • +
  • a cause, which is either nil or another error value that was the cause of +this error
  • a detail, which is an immutable mapping providing additional information about the error
  • a stack trace, which is an immutable snapshot of the state of the execution stack

-A module-qualified reason string is a string that has the form -

-
-   {org-name/module-name}identifier
-
-

-where org-name, module-name and -identifier are as defined by the grammar in this -specification, but with no whitespace allowed between tokens. Any reason string -that starts with a { should be a module-qualified reason string. -Any error value that is constructed as the associated value of a panic will use -a module-qualified reason with an org-name of ballerina and a -module-name that starts with lang., as will any error value -constructed by a function in the lang library. +The detail mapping must be a subtype of map<anydata|readonly>.

-The detail mapping must belong to the following type, which is provided as type -Detail in the lang.error module of the lang library: -

-
record {|
-   string message?;
-   error cause?;
-   (anydata|readonly)...;
-|};
-
-

-The shape of an error value consists of the shape of the reason and the shape of -the detail; the stack trace is not part of the shape. A type descriptor -error<r, d> contains an error shape if r -contains the shape's reason, and d, if present, contains the shape's -detail. The bare type error contains all error shapes. The -reason-type-descriptor must be a subtype of string. The detail-type-descriptor -must be a subtype of the Detail type, and defaults to the -Detail type if omitted. +The shapes of the message, cause and detail record are part of the shape of the +error; the stack trace is not part of the shape. A type descriptor +error<T> contains an error shape if +T contains the shape of the detail. The type +error contains a shape if its basic type is error.

A type of error<*> means that the type is a subtype of error, @@ -2888,15 +2865,21 @@

Functionally constructible types

defaults to empty string -error<R,D> +error<T> Position 1 -R, which will be a subtype of string -reason string -default to R if it is a singleton; otherwise, not allowed +string +message +not allowed + + +Position 2 +error? +cause +defaults to nil Name k -type of field k of D, which will be a +type of field k of T, which will be a subtype of anydata|readonly field k of detail record detail record has no field k @@ -7928,8 +7911,13 @@

Summary of changes from 2020R1 to 2020R2

  1. The readonly type has been added.
  2. Intersection types have been added.
  3. -
  4. Distinct types have been added; these provide the functionality -of nominal types with the framework of a structural type system.
  5. +
  6. Distinct types have been added; these provide the functionality of nominal +types with the framework of a structural type system.
  7. +
  8. The error type has been revised to take advantage of distinct types. Instead +an error value having a reason string for categorizing the error and separate +message string in the detail record, an error value has a message string in the +error and distinct types are used for categorizing. The cause has also moved +from the detail record into the error value.
  9. The table type has been redesigned to be more consistent with other structural types and no longer has preview status.
  10. Enum declarations have been added.