Lesson 6: Exception Handling Part 1
Nothing is loaded from YouTube until you press play, and then without tracking cookies.
About this video
For a better learning experience, sign up and enroll in this free course at: daml.talentlms.com/plus/catalog/courses/150
Transcript
1,951 wordsCaptions as YouTube publishes them, usually machine-generated, so names such as Daml and Canton can be misheard.
- 0:00
you might be familiar with some of the functions that are commonly employed for debugging and defining assertions these functions ensure that if a user attempts to create a contract or exercise a choice within valid input the transaction will be aborted however there are cases where completely aborting an invalid transaction might not be desirable instead you may prefer to handle the error and pursue an alternative approach based on your business logic
- 0:31
this lesson covers error handling and custom exceptions first let's quickly review some of the commonly used functions that could trigger errors to abort transactions as well as the functions available for debugging purposes ensure is used for specifying preconditions of contract creation it takes a Boolean as an argument if the Boolean evaluates to false it aborts the contract creation
- 1:04
assert and assert message are used for specifying assertions within a choice body they both take Boolean as an argument if the Boolean evaluates to false the transaction gets aborted unlike assert assert message also takes a text which gets printed when a transaction fails since assert doesn't print a helpful error message when a transaction fails assert message is recommended instead abort takes an error message it should
- 1:37
be used with caution since it unconditionally aborts a transaction debug and Trace are similar in that they both print messages however debug returns an empty action for the action it is being used in whether it is update or script while Trace returns whatever the second argument evaluates to note that when an error message is printed by calling one of these functions the message is visible only in the transaction view under Trace
- 2:11
this example shows The Social Network user template with the follow choice and the change Alias choice once a social network user contract is created controller can exercise the change Alias choice on it to update their alias however controller May provide an empty string as their new alias the transaction will be aborted as the insure expression doesn't allow the Alias field to be an empty string Let's
- 2:42
test it in the test script Alice creates a new Social Network user contract with an empty list for the following field and Alice Alias for the Alias field next Alice exercises the change Alias choice on the contract with an empty string as her new Alias which causes an error if it says unhandled exception d a exception precondition failed since change Alias is a default Choice once it's exercised the old contract
- 3:15
Alice CID gets archived additionally a new contract is created with a new Alias which is an empty string in this case in the process of the new contract creation with the new alias the precondition ensure Alias does not equal to an empty string evaluates to false and aborts the contract creation the precondition failed error occurred because that is the type of the exception thrown when an insure expression evaluates to false
- 3:49
while this lesson won't cover all the types of exceptions you can explore them further in the demo documentation now that the example produced an error let's talk about how to handle it one option to handle the error is to use the informative types such as either and optional they can specify which operations are allowed to fail without aborting the entire transaction that allows you to prevent an error from happening in the first place but there are two major downsides
- 4:21
first it can be invasive for operations where aborting the transaction is often the desired behavior for example if you modify the division operation to return an either or option type to handle division by zero it would require significant changes throughout the code base many parts of the code might not be prepared to handle the left value or none situation explicitly making the modification process extremely complicated second and more importantly this
- 4:55
approach does not allow rolling back Ledger actions that have happened before the point where the error was thrown when an error is thrown the default behavior in demo is to roll back all the changes that have happened until that point if a contract was created before the error occurred there is no way to undo it except to abort the entire transaction on the other hand exceptions let you
- 5:20
handle specific errors by allowing most code to be written as usual while providing clear control over which part of the current transaction should be rolled back upon failure instead of using the informative types you can let the error be thrown and handle the error using a try catch block first make the choice non-consuming then in the body of the choice open a tri-doo block to write the expression that could potentially cause an error in
- 5:52
the example it was the creation of a new contract with an empty string that through an error so archive the old contract and try to create a new contract within the tridu block as a reminder the self keyword refers to the contract ID of the contract which the choice is being exercised on the keyword this refers to the payload of the contract when a contract is created a record is created as the payload of the contract which can be referred as this
- 6:26
by passing this to create function a new contract is created using the old payload except that the field specified in the with block get updated you want everything else to remain the same when you update the Alias field with the new alias in the catch block you can specify the type of the error that might get thrown from the try block and Define how the program should continue in this case it was precondition failed which was thrown when the insure
- 6:57
expression evaluated to false to refer to a specific error type you must import the da exception library then you can pass an underscore as a parameter the underscore typically denotes the catch all case in pattern matching when applied to catching exceptions it signifies that you don't care if the exception carries any data after the right arrow which reads as maps to open a do block and write pure self to return the contract ID
- 7:32
alternatively you can replace pure self with Trace you can pass an error message as the first argument and pure self as the second argument as it Returns the contract ID of the existing contract it will also print the error message in the transaction View while some work Still Remains let's quickly recap your progress so far in terms of syntax first you turned a default choice to a non-consuming choice because when a
- 8:04
default choice is exercised the contract kits archived before the body of the choice is run a non-consuming choice leaves the contract active and allows you to Archive the contract within the body of the choice in the try block you attempt to Archive the contract and create a new one if it throws an error return the existing contracts ID in the catch block remember when writing a try catch that all three of the choice itself try block and catch block must have the same
- 8:37
return type or you will get a type check error also each try catch block can have multiple catch Clauses with the first one that applies taking precedence let's run the test script again this time instead of the error you saw earlier you get the custom message that you pass to the trace function in the transaction view 1 0 shows how Alice attempted to exercise change Alias with an empty string which was rolled back in one one
- 9:10
active contract remains to be zero zero which was the initial contract that was created before the choice was exercised with an empty string let's return to the code to continue while the try catch block may have worked correctly from a syntax perspective there are significant reasons why the code is not yet ready for production while using Trace to return self may seem reasonable in the development phase it is generally discouraged in production code the error message provided to trace is
- 9:44
only visible to developers in the transaction View and cannot be acted upon by the client application additionally returning pure self in this context means that the caller will receive a successful response even if the underlying operation has failed the caller will receive a successful response mistakenly assuming that the Alias has been changed however the change request was silently ignored which is a bug so let's fix it
- 10:14
first change the return type to be either text contract ID social network user then in the try block first archive the contract that the choice is exercised on then you bind the result of the create expression to the variable CID use the right Constructor to create a value of The Ether type where write C ID represents a successful outcome with a contract identifier then in the catch block use the left
- 10:46
Constructor to create a value of the either type where left Alias cannot be an empty string try again represents a failure outcome with an error message by changing the return type to either the choice becomes more expressive and provides clear information about the result it can now offer a successful outcome with a contract ID encapsulated in the right Constructor on the other hand if there is a failure it returns an error message within the left Constructor
- 11:20
in either case the output of the choice can be pattern matched and processed accordingly by utilizing either callers of the choice can easily handle and differentiate between success and failure scenarios let's run the test script you can see that the return value is encapsulated in the left Constructor note that this is a proper return value not just a text message visible in the transaction View on the other hand if you provide a valid
- 11:52
Alias such as expert damiler you receive a reference to a contract wrapped in the right Constructor indicating a successful outcome if you are curious to see the data that's carried by the precondition failed error replace the underscore with the variable EA as in the error argument which is typically a default error message you can pass this eea to debug to print the argument that was implicitly passed for creating the precondition failed error you can also encapsulate it in the left Constructor
- 12:26
for pattern matching once the test script is run everything else Remains the Same except that the default precondition failed error message gets printed instead of the custom message this indicates that the only argument passed to instantiate the precondition failed error was the default message alternatively you can write e precondition failed where the e is a variable of the type precondition failed to represent the error itself in this
- 12:58
case you can replace the argument of your debug expression with message e where message is a built-in function which takes an error and returns a message if the error contains an error message this lesson focused on using a try catch block for Effective error handling while you can proactively prevent errors by using informative types like either and optional it's important to consider that error prevention might not always be the best solution
- 13:29
there are scenarios where aborting the entire transaction and pursuing an alternative approach can yield better results in the demonstration you employed the either type not to prevent errors but rather to design alternate approaches within the try catch block for proper error handling