{"id":932,"date":"2015-08-24T13:49:57","date_gmt":"2015-08-24T12:49:57","guid":{"rendered":"http:\/\/benjiweber.co.uk\/blog\/?p=932"},"modified":"2018-08-11T17:54:33","modified_gmt":"2018-08-11T16:54:33","slug":"optionally-typechecked-statemachines","status":"publish","type":"post","link":"https:\/\/benjiweber.co.uk\/blog\/2015\/08\/24\/optionally-typechecked-statemachines\/","title":{"rendered":"Optionally typechecked StateMachines"},"content":{"rendered":"<p class=\"lead\">Many things can be modelled as <a href=\"https:\/\/en.wikipedia.org\/wiki\/Finite-state_machine\">finite state machines<\/a>. Particularly things where you&#8217;d naturally use &#8220;state&#8221; in the name e.g. the current state of an order, or delivery status. We often model these as enums. <\/p>\n<pre lang=\"java\">\r\nenum OrderStatus {\r\n    Pending,\r\n    CheckingOut,\r\n    Purchased,\r\n    Shipped,\r\n    Cancelled,\r\n    Delivered,\r\n    Failed,\r\n    Refunded\r\n}\r\n<\/pre>\n<p>Enums are great for restricting our order status to only valid states. However, usually there are only certain transitions that are valid. We can&#8217;t go from Delivered to Failed. Nor would we go straight from Pending to Delivered. Maybe we can transition from Purchased to either Shipped or Cancelled.<\/p>\n<p>Using enum values we cannot restrict to the transitions to only those that we desire. It would be nice to also let the compiler help us out by not letting us choose invalid transitions in our code. <\/p>\n<p>We can, however, achieve this if we use a class hierarchy to represent our states instead, and it can still be fairly concise. There are other reasons for using regular classes, they allow us to store and even capture state from the surrounding context. <\/p>\n<p>Here&#8217;s a way we could model the above enum as a class heirarchy with the valid transitions.<\/p>\n<pre lang=\"java\">\r\ninterface OrderStatus extends State<OrderStatus> {}\r\nstatic class Pending     implements OrderStatus, BiTransitionTo<CheckingOut, Cancelled> {}\r\nstatic class CheckingOut implements OrderStatus, BiTransitionTo<Purchased, Cancelled> {}\r\nstatic class Purchased   implements OrderStatus, BiTransitionTo<Shipped, Failed> {}\r\nstatic class Shipped     implements OrderStatus, BiTransitionTo<Refunded, Delivered> {}\r\nstatic class Delivered   implements OrderStatus, TransitionTo<Refunded> {}\r\nstatic class Cancelled   implements OrderStatus {}\r\nstatic class Failed      implements OrderStatus {}\r\nstatic class Refunded    implements OrderStatus {}\r\n<\/pre>\n<p>We&#8217;ve declared an OrderStatus interface and then created implementations of OrderStatus for each valid state. We&#8217;ve then encoded the valid transitions as other interface implementations. There&#8217;s a TransitionTo&lt;State&gt; and BiTransitionTo&lt;State1,State2&gt;, or TriTransitionTo&lt;State1,State2,State3&gt; depending on the number of valid transitions from that state. We need differently named interfaces for different numbers of transitions because Java doesn&#8217;t support variance on the number of generic type parameters.<\/p>\n<h2>Compile-time checking valid transitions<\/h2>\n<p>Now we can create the TransitionTo\/BiTransitionTo interfaces, which can give us the functionality to transition to a new state (but only if it is valid)<\/p>\n<p>We might imagine an api like this where we can choose which state to transition to<\/p>\n<pre lang=\"java\">\r\nnew Pending()\r\n    .transitionTo(CheckingOut.class)\r\n    .transitionTo(Purchased.class)\r\n    .transitionTo(Refunded.class) \/\/ <-- can we make this line fail to compile?\r\n<\/pre>\n<p>This turns out to be a little tricky, but not impossible, due to type erasure.<\/p>\n<p>Let's try to implement BiTransitionTo interface with the two valid transition.<\/p>\n<pre lang=\"java\">\r\npublic interface BiTransitionTo<T, U> {\r\n    default T transitionTo(Class<T> type) { ... }\r\n    default U transitionTo(Class<U> type) { ... }\r\n}\r\n<\/pre>\n<p>Both of these transitionTo methods have the <a href=\"http:\/\/stackoverflow.com\/questions\/1998544\/method-has-the-same-erasure-as-another-method-in-type\">same erasure<\/a>. So we can't do it quite like this. However, if we can encourage the consumer of our API to pass a lambda, there <a href=\"http:\/\/benjiweber.co.uk\/blog\/2015\/02\/20\/work-around-java-same-erasure-errors-with-lambdas\/\">is a way to work around this same erasure problem.<\/a><\/p>\n<p>So how about this API, where instead of passing class literals we pass constructor references. It looks similarly clean, but constructor references are basically lambdas so we can avoid type erasure.<\/p>\n<pre lang=\"java\">\r\nnew Pending()\r\n    .transition(CheckingOut::new)\r\n    .transition(Purchased::new)\r\n    .transition(Refunded::new) \/\/ <-- Now we can make this fail to compile\r\n<\/pre>\n<p><img src=\"https:\/\/benjiweber.co.uk\/b\/statemachine_typecheck.png\"\/><\/p>\n<p>In order to make this work the trick is to create a new interface type for each valid transition within our BiTransitionTo interface<\/p>\n<pre lang=\"java\">\r\npublic interface BiTransitionTo<T, U> {\r\n    interface OneTransition<T> extends Supplier<T> { }\r\n    default T transition(OneTransition<T> constructor) { ... }\r\n    interface TwoTransition<T> extends Supplier<T> { }\r\n    default U transition(TwoTransition<U> constructor) { ... }\r\n}\r\n<\/pre>\n<p>Supplier&lt;T&gt; is a functional interface in the java.util.function that is equivalent to a no-args constructor reference. By creating two interfaces that extend this we can overload the transition() method twice, allowing both methods to be passed a constructor reference without the two methods having the same erasure.<\/p>\n<h2>Runtime checking<\/h2>\n<p>Sometimes we might not be able to know at compile-time what state our statemachine is in. Perhaps a Customer has a field of type OrderStatus that we serialize to a database.  We would need to be able to try a transition at runtime, and fail in some manner if the transition is not valid.<\/p>\n<p>This is also possible using the TransitionTo&lt;NewState&gt; approach outlined above. Since supertype parameters <a href=\"http:\/\/gafter.blogspot.co.uk\/2006\/12\/super-type-tokens.html\">are available at runtime<\/a>, we can implement a tryTransition() method that uses reflection to check which transitions are permitted.<\/p>\n<p>First we'll need a way of finding the valid transition types. We'll add it to our State base interface.<\/p>\n<pre lang=\"java\">\r\ndefault List<Class<?>> validTransitionTypes() {\r\n    return asList(getClass().getGenericInterfaces())\r\n        .stream()\r\n        .filter(type -> type instanceof ParameterizedType)\r\n        .map(type -> (ParameterizedType) type)\r\n        .filter(TransitionTo::isTransition) \r\n        .flatMap(type -> asList(type.getActualTypeArguments()).stream())\r\n        .map(type -> (Class<?>) type)\r\n        .collect(toList());\r\n}\r\n<\/pre>\n<p>Note the isTransition filter. Since we have multiple transition interfaces - TransitionTo&lt;T&gt;, BiTransitionTo&lt;T,U&gt;, TriTransitionTo&lt;T,U,V&gt; etc, we need a way of marking them as all specifying transitions. I've used an annotation <\/p>\n<pre lang=\"java\">\r\n@Retention(RUNTIME)\r\n@Target(ElementType.TYPE)\r\npublic @interface Transition {\r\n\r\n}\r\nstatic boolean isTransition(ParameterizedType type) {\r\n     Class<?> cls = (Class<?>)type.getRawType();\r\n     return cls.getAnnotationsByType(Transition.class).length > 0;\r\n}\r\n\r\n@Transition\r\npublic interface TriTransitionTo...\r\n<\/pre>\n<p>Once we have validTransitionTypes() we can find which transitions are valid at runtime.<\/p>\n<pre lang=\"java\">\r\nstatic class Pending implements OrderStatus, BiTransitionTo<CheckingOut, Cancelled> {}\r\n@Test\r\npublic void finding_valid_transitions_at_runtime() {\r\n    Pending pending = new Pending();\r\n    assertEquals(\r\n        asList(CheckingOut.class, Cancelled.class),\r\n        pending.validTransitionTypes()\r\n    );\r\n}\r\n<\/pre>\n<p>Now that we have the valid types, tryTransition() needs to check whether the requested transition is to one of those types. <\/p>\n<p>This is a little tricky, but since we're passing a lambda we make it a <a href=\"http:\/\/benjiweber.co.uk\/blog\/2015\/08\/04\/lambda-type-references\/\">lambda-type-token<\/a> and use reflection to find the type parameter of the lambda.<\/p>\n<p>Our implementation then looks something like <\/p>\n<pre lang=\"java\">\r\n\r\ninterface NextState<T> extends Supplier<T>, MethodFinder {\r\n    default Class<T> type() {\r\n        return (Class<T>) getContainingClass();\r\n    }\r\n}\r\ndefault <T> T tryTransition(NextState<T> desired) {\r\n    if (validTransitionTypes.contains(desired.type())) {\r\n        return desired.get();\r\n    }\r\n\r\n    throw new IllegalStateTransitionException();\r\n}\r\n<\/pre>\n<p>We can make it a bit nicer by allowing the caller to specify the exception to throw on error, like an Optional's orElseThrow. We can also allow the caller to ignore failed transitions.<\/p>\n<pre lang=\"java\">\r\n@Test\r\npublic void runtime_checked_transition() {\r\n    OrderStatus state = new Pending();\r\n    assertTrue(state instanceof Pending);\r\n    state = state\r\n        .tryTransition(CheckingOut::new)\r\n        .unchecked();\r\n    assertTrue(state instanceof CheckingOut);\r\n}\r\n<\/pre>\n<p>Since we've transitioned into a known state (or thrown an exception) with tryTransition we could then chain compile-time checked transitions on the end.<\/p>\n<pre lang=\"java\">\r\n@Test\r\npublic void runtime_checked_transition() {\r\n    OrderStatus state = new Pending();\r\n    assertTrue(state instanceof Pending);\r\n    state = state\r\n        .tryTransition(CheckingOut::new)\r\n        .unchecked()\r\n        .transition(Purchased::new); \/\/ This will be permitted if the tryTransition succeeds.\r\n    assertTrue(state instanceof CheckingOut);\r\n}\r\n<\/pre>\n<p>We can even let people ignore transition failures if they wish, just by catching the exception and returning the original value.<\/p>\n<pre lang=\"java\">\r\n@Test\r\npublic void runtime_checked_transition_ignoring_failure() {\r\n    OrderStatus state = new Pending();\r\n    assertTrue(state instanceof Pending);\r\n    state = state\r\n        .tryTransition(Refunded::new)\r\n        .ignoreIfInvalid();\r\n    assertFalse(state instanceof Refunded);\r\n    assertTrue(state instanceof Pending);\r\n}\r\n<\/pre>\n<h2>Adding Behaviour<\/h2>\n<p>Since our states are classes, we can add behaviour to them. <\/p>\n<p>For instance we could add a notifyProgress() method to our OrderStatus, with different implementations in each state.<\/p>\n<pre lang=\"java\">\r\ninterface OrderStatus extends State<OrderStatus> {\r\n    default void notifyProgress(Customer customer, EmailSender sender) {}\r\n}\r\nstatic class Purchased implements OrderStatus, BiTransitionTo<Shipped, Failed> {\r\n    public void notifyProgress(Customer customer, EmailSender emailSender) {\r\n        emailSender.sendEmail(\"fulfillment@mycompany.com\", \"Customer order pending\");\r\n        emailSender.sendEmail(customer.email(), \"Your order is on its way\");\r\n    }\r\n}\r\n...\r\nOrderStatus status = new Pending();\r\nstatus.notifyProgress(customer, sender); \/\/ Does nothing\r\nstatus = status\r\n    .tryTransition(CheckingOut::new)\r\n    .unchecked()\r\n    .transition(Purchased::new);\r\nstatus.notifyProgress(customer, sender) ; \/\/ sends emails\r\n<\/pre>\n<p>Then we can call notifyProgress on any OrderStatus instance and it will notify differently depending on which implementation is active.<\/p>\n<h2>Internal Transitions<\/h2>\n<p>One of the ways to make most use of the typechecked transitions is to have the transitions internally within the state. e.g. in a state machine for the Regex \"A+B\" the A state can transition either <\/p>\n<ul>\n<li>Back to A<\/li>\n<li>To B<\/li>\n<li>To a match failure state<\/li>\n<\/ul>\n<p>If we do this we can make them typechecked even though we don't know what the string we're matching in advance is.<\/p>\n<pre lang=\"java\">\r\nstatic class A implements APlusB, TriTransitionTo<A,B,NoMatch> {\r\n    public APlusB match(String s) {\r\n        if (s.length() < 1) return transition(NoMatch::new);\r\n        if (s.charAt(0) == 'A') return transition(A::new).match(s.substring(1));\r\n        if (s.charAt(0) == 'B') return transition(B::new).match(s.substring(1));\r\n        return transition(NoMatch::new);\r\n    }\r\n}\r\n<\/pre>\n<p><a href=\"https:\/\/github.com\/benjiman\/statemachine\/blob\/master\/src\/test\/java\/com\/benjiweber\/statemachine\/RegexExample.java\">Full example here<\/a><\/p>\n<h2>Capturing State<\/h2>\n<p>If we use non-static classes we could also capture state from the enclosing class. Supposing these OrderStatuses are contained within an Order class that already has an EmailSender available, we'd no longer need to pass in the emailSender and the customer to the notifyProgress() method.<\/p>\n<pre lang=\"java\">\r\nclass Order {\r\n    EmailSender emailSender;\r\n    Customer customer;\r\n    class Purchased implements OrderStatus, BiTransitionTo<Shipped, Failed> {\r\n        public void notifyProgress() {\r\n            emailSender.sendEmail(\"fulfillment@mycompany.com\", \"Customer order pending\");\r\n            emailSender.sendEmail(customer.email(), \"Your order is on its way\");\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<h2>Guards<\/h2>\n<p>Another feature we might want is the ability to execute some code before transitioning into a new state or after transitioning into a new state. This is something we can add to our base State interface. Let's add two methods beforeTransition() and afterTransition()<\/p>\n<pre lang=\"java\">\r\ninterface State {\r\n    default void afterTransition(T from) {}\r\n    default void beforeTransition(T to) {}\r\n}\r\n<\/pre>\n<p>We can then update our transition implementation to invoke these guard methods before and after a transition occurs.<\/p>\n<p>We could use this to log all transitions into the Failure state.<\/p>\n<pre lang=\"java\">\r\nclass Failed implements OrderStatus {\r\n    @Override\r\n    public void afterTransition(OrderStatus from) {\r\n        failureLog.warning(\"Oh bother! failed from \" + from.getClass().getSimpleName());\r\n    }\r\n}\r\n<\/pre>\n<p>We could also combine state capturing and guard methods to build a stateful-state machine that updates its state on transition instead of just returning the new state. Here's an example where we use a guard method to mutate the state of lightSwitch after each transition.<\/p>\n<pre lang=\"java\">\r\nclass LightExample {\r\n    Switch lightSwitch = new Off();\r\n\r\n    public class Switch implements State<Switch> {\r\n        @Override\r\n        public void afterTransition(Switch from) {\r\n            LightExample.this.lightSwitch = Switch.this;\r\n        }\r\n    }\r\n    public class On extends Switch implements TransitionTo<Off> {}\r\n    public class Off extends Switch implements TransitionTo<On> {}\r\n\r\n    @Test\r\n    public void stateful_switch() {\r\n        assertTrue(lightSwitch instanceof Off);\r\n        lightSwitch.tryTransition(On::new).ignoreIfInvalid();\r\n        assertTrue(lightSwitch instanceof On);\r\n        lightSwitch.tryTransition(Off::new).ignoreIfInvalid();\r\n        assertTrue(lightSwitch instanceof Off);\r\n    }\r\n}\r\n<\/pre>\n<h2>Show me the code<\/h2>\n<p>The <a href=\"https:\/\/github.com\/benjiman\/statemachine\">code is on github<\/a> if you'd like to play with it\/see full executable examples<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Many things can be modelled as finite state machines. Particularly things where you&#8217;d naturally use &#8220;state&#8221; in the name e.g. the current state of an order, or delivery status. We often model these as enums. enum OrderStatus { Pending, CheckingOut, Purchased, Shipped, Cancelled, Delivered, Failed, Refunded } Enums are great for restricting our order status&#8230;  <a href=\"https:\/\/benjiweber.co.uk\/blog\/2015\/08\/24\/optionally-typechecked-statemachines\/\" class=\"more-link\" title=\"Read Optionally typechecked StateMachines\">Read more &raquo;<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[8],"tags":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v14.9 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/benjiweber.co.uk\/blog\/2015\/08\/24\/optionally-typechecked-statemachines\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Optionally typechecked StateMachines - Benji&#039;s Blog\" \/>\n<meta property=\"og:description\" content=\"Many things can be modelled as finite state machines. Particularly things where you&#8217;d naturally use &#8220;state&#8221; in the name e.g. the current state of an order, or delivery status. We often model these as enums. enum OrderStatus { Pending, CheckingOut, Purchased, Shipped, Cancelled, Delivered, Failed, Refunded } Enums are great for restricting our order status... Read more &raquo;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/benjiweber.co.uk\/blog\/2015\/08\/24\/optionally-typechecked-statemachines\/\" \/>\n<meta property=\"og:site_name\" content=\"Benji&#039;s Blog\" \/>\n<meta property=\"article:published_time\" content=\"2015-08-24T12:49:57+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-08-11T16:54:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/benjiweber.co.uk\/b\/statemachine_typecheck.png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/#website\",\"url\":\"https:\/\/benjiweber.co.uk\/blog\/\",\"name\":\"Benji&#039;s Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/benjiweber.co.uk\/blog\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/2015\/08\/24\/optionally-typechecked-statemachines\/#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/benjiweber.co.uk\/b\/statemachine_typecheck.png\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/2015\/08\/24\/optionally-typechecked-statemachines\/#webpage\",\"url\":\"https:\/\/benjiweber.co.uk\/blog\/2015\/08\/24\/optionally-typechecked-statemachines\/\",\"name\":\"Optionally typechecked StateMachines - Benji&#039;s Blog\",\"isPartOf\":{\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/2015\/08\/24\/optionally-typechecked-statemachines\/#primaryimage\"},\"datePublished\":\"2015-08-24T12:49:57+00:00\",\"dateModified\":\"2018-08-11T16:54:33+00:00\",\"author\":{\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/#\/schema\/person\/45ecb36b51f4ce99e6929d2d31ca5c09\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/benjiweber.co.uk\/blog\/2015\/08\/24\/optionally-typechecked-statemachines\/\"]}]},{\"@type\":\"Person\",\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/#\/schema\/person\/45ecb36b51f4ce99e6929d2d31ca5c09\",\"name\":\"benji\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/benjiweber.co.uk\/blog\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/05fb47b31a0b329e1b790074a9b624ef?s=96&d=mm&r=g\",\"caption\":\"benji\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","amp_enabled":true,"_links":{"self":[{"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/posts\/932"}],"collection":[{"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=932"}],"version-history":[{"count":20,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/posts\/932\/revisions"}],"predecessor-version":[{"id":1268,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/posts\/932\/revisions\/1268"}],"wp:attachment":[{"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=932"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=932"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/benjiweber.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=932"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}