{"id":2624,"date":"2017-04-25T12:25:06","date_gmt":"2017-04-25T00:25:06","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2624"},"modified":"2017-04-25T15:19:39","modified_gmt":"2017-04-25T03:19:39","slug":"expressive-if-and-case","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2624\/","title":{"rendered":"Expressive If and Case &#8230;"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 2<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>A quick post on a small but hugely useful little language feature in Oxygene&#8230; <strong>if<\/strong> expressions.<\/p>\n<p><!--more--><\/p>\n<p>Many people will be familiar with the so-called <em><a href=\"https:\/\/en.wikipedia.org\/wiki\/%3F:\">ternary operator<\/a><\/em>.  Delphi developers will also be aware that there is no direct equivalent in Delphi.<\/p>\n<p>In &#8216;C&#8217; and other languages we can write a statement such as this:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n    x = a ? b : c;\r\n<\/pre>\n<p>The result is that <strong>x<\/strong> is assigned the value of <strong>b<\/strong> when <strong>a<\/strong> is <em>true<\/em>, otherwise <strong>x<\/strong> is assigned the value of <strong>c<\/strong>.<\/p>\n<p>The ternary operator evaluates only either <strong>b<\/strong> or <strong>c<\/strong> as determined by the condition <strong>a<\/strong>.<\/p>\n<p>In Delphi you can use the <strong>IfThen()<\/strong> function (for supported types of values of <strong>b<\/strong> and <strong>c<\/strong>) but this is notorious for the short-coming that regardless of the value of condition <strong>a<\/strong> both <strong>b<\/strong> and <strong>c<\/strong> will be evaluated.<\/p>\n<p>At best this makes <strong>IfThen()<\/strong> potentially less efficient and at worst it can render it entirely useless if the evaluation of <strong>b<\/strong> or <strong>c<\/strong> has undesirable consequences or side-effects.<\/p>\n<p>For example if you tried to use <strong>IfThen()<\/strong> to avoid a division by zero:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n     x := IfThen( divisor &lt;&gt; 0, numerator div divisor, 0);\r\n<\/pre>\n<p>This code will still throw a division by zero exception when <strong>divisor<\/strong> = zero.  The equivalent ternary expression would not:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n     x = divisor != 0 ? numerator \/ divisor : 0;\r\n<\/pre>\n<p>In Delphi therefore you have no choice in these situations but to long-hand an <strong>if-else<\/strong> statement:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n   if divisor &lt;&gt; 0 then\r\n     x := numerator div divisor\r\n   else\r\n     x := 0;\r\n<\/pre>\n<p>In Delphi therefore it is not uncommon to find this one, simple problem solved by at least three different techniques:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n    \/\/ 1. Where the values of b and c are supported by IfThen\r\n    \/\/     and have no side effects:\r\n\r\n    x := IfThen( a, b, c );\r\n\r\n\r\n    \/\/ 2. Where b and\/or c are variable expressions that \r\n    \/\/     do or may have side-effects:\r\n\r\n    if a then\r\n      x := b\r\n    else\r\n      x := c;\r\n\r\n\r\n    \/\/ 3. Where the values of b and c are constant expressions:\r\n\r\n    const\r\n      AVALUE: array&#x5B;false..true] of Integer = (0, 42);\r\n\r\n    x := AVALUE&#x5B;a];\r\n\r\n<\/pre>\n<p>Oxygene addresses this gap by simply re-purposing the <strong>if<\/strong> statement as an expression:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n  x := if divisor &lt;&gt; 0 then numerator div divisor else 0;\r\n<\/pre>\n<p>But Oxygene also goes further, extending the same behaviour to <strong>case<\/strong> statements, for example:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n   x := case selector of\r\n     CONST_A : valueA;\r\n     CONST_B : valueB;\r\n     CONST_C : valueC;\r\n   end;\r\n<\/pre>\n<p>Applying <strong>case<\/strong> and <strong>if<\/strong> in this way eliminates the duplication of the assignment expression in the overall statement and can be applied consistently in other scenarios such as choosing values to pass as parameters to functions:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n   Foo( a, if a &gt; 42 then b else c );\r\n<\/pre>\n<p>The result is code that is consistent as well as both (imho) more concise and also clearer in intent than an <strong>if-else<\/strong> or (for <em>case<\/em>) a series of <strong>if-else if-else if<\/strong> statements.<\/p>\n<p>Although a seemingly very small thing it is one of my favorite features of the Oxygene implementation of Object Pascal.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 2<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>A quick post on a small but hugely useful little language feature in Oxygene&#8230; if expressions.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[4],"tags":[125,320,13,127,181],"class_list":["post-2624","post","type-post","status-publish","format-standard","hentry","category-delphi","tag-case","tag-if","tag-language","tag-object-pascal","tag-oxygene-2"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-Gk","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2624","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=2624"}],"version-history":[{"count":7,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2624\/revisions"}],"predecessor-version":[{"id":2631,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2624\/revisions\/2631"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2624"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2624"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2624"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}