TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Ternary Operators

68 pointsby azhenley6 months ago

29 comments

dan-robertson6 months ago
First example that came to mind for me is in SQL:<p><pre><code> x IS BETWEEN y AND z </code></pre> A not-quite-binary example would be languages where comparisons chain:<p><pre><code> x &lt; y &lt;= z Equivalent to: (x &lt; y) &amp;&amp; (y &lt;= z) (Possibly modulo short-circuiting) </code></pre> In maths, you would sometimes see clever constructions with reversed relation symbols to succinctly describe many things at once; when written down I would sometimes see relations going out in other directions after left and right were exhausted.<p>The ‘ternary’ assignment is customisable in OCaml: x.(y) &lt;- z is (maybe was?) exactly equivalent Array.set x y z, including in the parse tree, and so could be can be customised by shadowing the Array module; and custom variants may be defined too, e.g.<p><pre><code> type &#x27;a t = {mutable a : &#x27;a array; mutable p : int } let push t x = ensure_capacity t 1; t.a.(t.p) &lt;- x; t.p &lt;- t.p + 1 let (.:()&lt;-) t j x = if j &gt;= t.p then raise Out_of_bounds; t.a.(j) &lt;- x (* one can now use t.:(i) &lt;- x *) </code></pre> Another weirder mixfix example would be binding operators, but then you accept lots of other syntax too like if then else. Binding operators let you define weird functions with names like (let<i>) or (and</i>) and then:<p><pre><code> let* x = y in z (* equivalent to: *) (let*) y (fun x -&gt; z) let* x1 = y1 and x2 = y2 in z (* equivalent to: *) (let*) ((and*) y1 y2) (fun (x1, x2) -&gt; z)</code></pre>
评论 #42058682 未加载
seanhunter6 months ago
What about the derivative operator in maths? When you write say d^nf&#x2F;dx^n in Leibniz notation (or the equivalent in Lagrange notation f^(n)(x)), you have 3 arguments. The &quot;f&quot; is the function you are taking the derivative of, the n is what derivative to take and then the (x) is what to name the argument in the resulting function.<p>Obviously in the common case you&#x27;re just writing something like f&#x27;(x) or f&#x27;&#x27;(x) where the &#x27; stands for ^(1) but it&#x27;s still a ternary operator.<p>Another common example in maths is the &quot;limit&quot; operator where you have lim_x-&gt;a &lt;someexpr&gt; and the arguments are x, a and someexpr.
评论 #42055585 未加载
评论 #42055426 未加载
taeric6 months ago
Agreed with a sibling that this is somewhat abusing the terminology. In&#x2F;pre&#x2F;postfix of the operators is a different thing from how many terms an operator acts on. Indeed, in RPN, it was not uncommon to try and execute an operator but not have enough terms on the stack.<p>Seems that we typically call the ?: combination a ternary operator largely stems from the distinction between operators, functions, and keywords. One that we largely don&#x27;t keep in a consistent fashion. Add in functions versus methods, and things get really fun.<p>Programming also has the odd case where functions have an easy syntax to say that there are multiple inputs, but we don&#x27;t have a common syntax to say there are multiple outputs. Which is something that is quite common in every domain.
评论 #42055549 未加载
pistoleer6 months ago
After some thinking, the ternary conditional operator can be decomposed into 2 composing binary operators like such:<p>? takes a bool, a T, and returns option&lt;T&gt;<p>true?b == Result b<p>false?b == None<p>: takes an Option&lt;T&gt; and a T and returns T<p>Result x : y == x<p>None : y == y<p>However, in most languages (looking at you php) the ?: act as a type of parenthesis: in a?b:c, any expression goes into b, no matter it&#x27;s precedence.
评论 #42056413 未加载
评论 #42056566 未加载
mjw10076 months ago
JavaScript method call notation is arguably a ternary operator, or a candidate for the &quot;Near Misses&quot; list (because « foo.bar(x) » isn&#x27;t the same as « var meth = foo.bar; meth(x) »).
评论 #42055489 未加载
评论 #42054928 未加载
Etheryte6 months ago
The whole article hinges on the fact that the author seems to be unfamiliar with the term arity (?), which feels weird given they&#x27;re clearly familiar with a number of programming languages etc. The definitions for unary, binary, etc are rather arbitrary and not how they&#x27;re usually used.
评论 #42054898 未加载
评论 #42055704 未加载
评论 #42054977 未加载
not2b6 months ago
Verilog has a sliding-window part select, which produces a slice that has a fixed width. It&#x27;s an lvalue expression (it can be assigned to). It&#x27;s ternary.<p>array[addr +: W]<p>or<p>array[addr -: W]<p>The former chooses W elements beginning at addr, the latter chooses W elements ending at addr.
评论 #42055895 未加载
zokier6 months ago
(postgre)sql has lots of quirky stuff that kinda qualifies. For example<p><pre><code> substring ( string text [ FROM start integer ] [ FOR count integer ] ) → text </code></pre> at a glance you might think that as just a normal function call, but the arguments do not follow the regular function call argument syntax, instead it has this special sauce ternary syntax.
readthenotes16 months ago
Binary operators don&#x27;t &quot;go between&quot; 2 operands, they just consume two operands.<p>+ 2 3<p>Is a perfectly valid binary operator.
评论 #42054616 未加载
o11c6 months ago
It mentions ranges, but not slices?<p>Note that the &quot;conditional&#x2F;selection operator&quot; is normally thought of as a logical operator, but variants exist that operate bitwise `r = (if_false &amp; ~condmask) | (if_true &amp; condmask)` or on a vector. Additionally, there maybe a special versions that operate at compile-time instead of runtime.<p>Modular exponentiation is commonly implemented as ternary for major performance improvements, even though technically it can be done as composition of two binaries.<p>Modular congruence `3 === 1 (mod 2)` is common in math.<p>Many arithmetic and bitwise operations take a third argument for the carry bit. Rotates are notable for actually performing a different operation in that case.<p>There are various SIMD operations.<p>There&#x27;s also SSA.
abrudz6 months ago
APL brings another couple of ternaries (besides for those mentioned with regards to J):<p><pre><code> x f[k] y </code></pre> This one is universal among traditional APLs (though some modern APLs, including J, remove it). However, it is traditionally only used for a concept of application along an axis of APL&#x27;s multidimentional arrays, and only for a strictly limited set of built-in &quot;operators&quot;. That said, GNU APL and NARS2000 both allow it on user-defined functions (which have infix syntax, just like &quot;operators&quot;).<p><pre><code> x n.f y </code></pre> This is infix application of the function f from the namespace n, so n must have namespace value, but it is still a proper argument because n isn&#x27;t just an identifier, but can also be an expression:<p><pre><code> x (expression).f y </code></pre> In fact, the expression can be an entire (multidimentional!) array of namespaces:<p><pre><code> x (namespace1 namespace2).f y </code></pre> is equivalent to<p><pre><code> (x[1] namespace1.f y[1])(x[2] namespace2.f y[2]) </code></pre> Furthermore, f can be a built-in &quot;operator&quot; which appears to exist in every namespace, but which also takes the current namespace into consideration. For example, x⍳y is the position of y in x and if io0 is a namespace wherein indexing is 0-based and io1 is a namespace wherein indexing is 1-based, we can write:<p><pre><code> &#x27;AX&#x27; &#x27;BX&#x27; (ns0 ns1).⍳ &#x27;X&#x27; </code></pre> and get the result 1 2 because X is at position 1 in AX with 0-based indexing but at position 2 of BX with 1-based indexing. (I&#x27;m not saying you should write code like this, but you <i>could</i>.)
zusammen6 months ago
I’m surprised not to see fused multiply-add here:<p><pre><code> FMA(x,y,z) ~ x += y*z </code></pre> You see it all over the place in numerical computing and deep learning.
评论 #42055106 未加载
bediger40006 months ago
In Tarski&#x27;s axiomatization of plane geometry, there&#x27;s a betweenness triadic relationship, Bxyz, point y is between x and z.
Cieric6 months ago
I&#x27;m not sure I&#x27;d say that it can&#x27;t be done. In some languages it could be implemented if the language itself supports optionals. So &quot;bool ? x&quot; could result in an Optional&lt;type(x)&gt;, while &quot;Optional&lt;type(x)&gt; : y&quot; could be the typical implementation of value_or that is found on optionals.<p>Whether it&#x27;s a good idea to implement it that way is something I haven&#x27;t come to an opinion on yet. My only argument is that &quot;can&#x27;t be decomposed&quot; feels like it&#x27;s a little to far reaching.<p>Edit: to add on to this, while it&#x27;s not really a ternary operator in the sense he seems to be looking for. It it common for assembly to have fma instructions. But this feels like a really weird edge case since x * y + z technically can be decomposed into the 2 separate operators, but the fma instruction itself can&#x27;t be decomposed without losing precision.
评论 #42055126 未加载
thesz6 months ago
In Agda, if_then_else_ is a ternary operator: <a href="https:&#x2F;&#x2F;wiki.portal.chalmers.se&#x2F;agda&#x2F;ReferenceManual&#x2F;Mixfix" rel="nofollow">https:&#x2F;&#x2F;wiki.portal.chalmers.se&#x2F;agda&#x2F;ReferenceManual&#x2F;Mixfix</a><p>For Agda being lazily evaluated, ternary if_then_else_ corresponds to usual <i>if cond then true_expr else else_expr</i> syntax of most mainstream languages.<p>Maude also have a lot of infix, prefix, postfix and mixfix, including ternary operations: <a href="https:&#x2F;&#x2F;maude.cs.uiuc.edu&#x2F;maude1&#x2F;manual&#x2F;maude-manual-html&#x2F;maude-manual_31.html" rel="nofollow">https:&#x2F;&#x2F;maude.cs.uiuc.edu&#x2F;maude1&#x2F;manual&#x2F;maude-manual-html&#x2F;ma...</a>
Izkata6 months ago
Missed python&#x27;s slicing:<p><pre><code> &gt;&gt;&gt; &#x27;abcdefghijklmnopqrstuvwxyz&#x27;[1:20:4] &#x27;bfjnr&#x27; </code></pre> It&#x27;s start&#x2F;end&#x2F;skip, with default values of 0, length, 1; each can be omitted so it&#x27;s rare to see the third one unless someone is showing off how to reverse a string:<p><pre><code> &gt;&gt;&gt; &#x27;abcdefghijklmnopqrstuvwxyz&#x27;[::-1] &#x27;zyxwvutsrqponmlkjihgfedcba&#x27; </code></pre> Though really these are slice objects, it&#x27;s just the syntax only works inside array access:<p><pre><code> &gt;&gt;&gt; slice &lt;class &#x27;slice&#x27;&gt; &gt;&gt;&gt; z = slice(1, 20, 4) &gt;&gt;&gt; &#x27;abcdefghijklmnopqrstuvwxyz&#x27;[z] &#x27;bfjnr&#x27;</code></pre>
评论 #42056039 未加载
jcarrano6 months ago
They are all just functions. There is really no distinction between an operator and a function in programming languages. And by using currying you could even do with just unary operators.
评论 #42056773 未加载
JadeNB6 months ago
I don&#x27;t understand why `a += b` is called binary (I agree!) but `a f= b` would be called ternary. I guess it&#x27;s thinking of `f` as one of the arguments?
评论 #42056370 未加载
zX41ZdbW6 months ago
SQL has a BETWEEN AND operator:<p><pre><code> SELECT count() FROM hits WHERE EventDate BETWEEN &#x27;2024-01-01&#x27; AND &#x27;2024-11-11&#x27; </code></pre> <a href="https:&#x2F;&#x2F;clickhouse.com&#x2F;docs&#x2F;en&#x2F;sql-reference&#x2F;operators" rel="nofollow">https:&#x2F;&#x2F;clickhouse.com&#x2F;docs&#x2F;en&#x2F;sql-reference&#x2F;operators</a>
zarzavat6 months ago
clamp and mix are good candidates. Ternary operator syntaxes are rarer than ternary operations, because there&#x27;s not much that can justify being so syntactically indulgent.<p>Conditionals are common enough that they can justify the indulgence, but even then I prefer an if-else expression syntax over ?:, it generalises better to other constructs such as pattern matching.
评论 #42055933 未加载
ks20486 months ago
Like others here, I find the way this article discusses things a bit odd. I think a more interesting question is to emphasize SYNTAX (the word doesn’t seem to appear in the article). Which languages have special syntax that maps to an AST node as OP(a,b,c)? Focus on syntax and things like range(start,end,step) dont fall into this category.
评论 #42055393 未加载
rurban6 months ago
Beware the number of evaluation dragons!<p>1 &lt; x &lt; 5 is not just syntactic sugar for 1 &lt; x and x &lt; 5.<p>Every lisp macro programmer knows that x must be evaluated only once, so it needs to be gensym&#x27;ed. Only if x is a constant or evaluates to itself it can be optimized without a gensym.
评论 #42083971 未加载
karmakaze6 months ago
I rather like the Smalltalk message selector structure Boolean&gt;&gt;ifTrue:ifFalse:<p><pre><code> (cond) ifTrue: [then-block] ifFalse: [else-block] </code></pre> For some reason the way Swift handles syntax I find less memorable or composable.
lilyball6 months ago
When talking about J forks, the author says they don&#x27;t know how to parse `x (f1 f2 f3 f4 f5) y`. After reading the relevant documentation, I believe this parses as<p><pre><code> (x f1 y) f2 ((x f3 y) f4 (x f5 y))</code></pre>
评论 #42055986 未加载
kragen6 months ago
Maybe it was Dave Long that pointed out that lerp is a generalization of the conditional ternary operator. When the condition is 0, it returns the from-point, and when it&#x27;s 1, it returns the to-point, but if you generalize it to the whole real number line, you lose nothing semantically except for short-circuiting. Lerp is a pretty common <i>function</i> in graphics—the simplest way to understand Bézier splines is as recursive lerping—but for whatever reason it generally isn&#x27;t written as an infix operator, which seems to be what Hillel is looking for here.<p>I think that Hillel&#x27;s criterion that the ternary operator &quot;can&#x27;t be decomposed into two sequential binary operators&quot; is too demanding. He says, &quot;<i>bool ? x</i> makes no sense on its own, nor does <i>x : y</i>&quot;. Well, that&#x27;s just because C&#x27;s grammar is written such that they won&#x27;t parse. If you extend the grammar to permit them, it&#x27;s not very hard to extend the semantics as well. For example, you could permit every expression to either succeed, yielding a value, or fail, yielding no value; languages that work in something like this way include regular expressions, META-II, Icon, Unicon, and Prolog, though each of them deviates from it in detail. Then, to get the C&#x2F;JS semantics, <i>bool ? x</i> succeeds with the value of <i>x</i> if <i>bool</i> is true, or fails if <i>bool</i> is false, and <i>x : y</i> succeeds with the value of <i>x</i> if <i>x</i> succeeds, but if <i>x</i> fails, does <i>y</i>.<p>You could model the exception mechanism in languages with exceptions as failing to return a value, in which case <i>x : y</i> ends up being a general-purpose exception-handling mechanism, so you can say something like <i>total[k] = (total[k] : 0) + 1</i> to increment a possibly-nonexistent hash key. Mark Lentczner&#x27;s language Wheat has an operator like this, spelled <i>!!</i>, which I stole for my own language Bicicleta.<p>(That&#x27;s assuming you parse <i>bool ? x : y</i> as <i>(bool ? x) : y</i>. You can also invent semantics that give you the right behavior with the parsing <i>bool ? (x : y)</i> but the ones that occur to me seem less appealing.)<p>Similarly for Elixir&#x27;s stepped range 1..10&#x2F;&#x2F;2. Hillel says, &quot;This isn&#x27;t decomposable into two binary ops because you can&#x27;t assign the range to a value and then step the value later.&quot; Well, maybe not (I don&#x27;t know Elixir), but it seems clear enough what <i>r&#x2F;&#x2F;2</i> should do if <i>r</i> is the name of a range value: it should produce a new range stepping either by 2 or by twice the previous step.<p>C++ does something like this for Hillel&#x27;s (or munificent&#x27;s) example of <i>a[b] = c</i>: the expression <i>a[b]</i> evaluates to a reference, which in rvalue context decays to an ordinary value, but which can indeed be assigned to a variable. Unfortunately, C++&#x27;s reference semantics are somewhat weak, with the consequence that actually overriding <i>operator[]</i> in C++ to return a reference is pretty bug-prone, because you can autovivify things you didn&#x27;t want to autovivify.<p>By Hillel&#x27;s apparent syntactic and decomposability criteria, I think every single two-argument method in Smalltalk is a &quot;ternary operator&quot;. <i>1 to: anInt do: [ :i | r := ( r * self ) ]</i>, for example, or <i>arr at: i put: v</i>. As he sort of points out, Objective-C inherited this from its Smalltalk roots, but he sort of throws up his hands at it.
评论 #42055458 未加载
评论 #42057137 未加载
librasteve6 months ago
interesting collection… I would propose the raku sequence op `…` as a ternary, for example:<p><pre><code> 1,2,3 … Inf; #(1,2,3,4,5,6…) arithmetic sequence 1,2,4 … Inf; #(1,2,4,8,16,32…) geometric sequence </code></pre> so looks at all three of the operands to work out the result
adonovan6 months ago
Why doesn’t the article mention the most obvious example of all, s[i:j]?
plaidphantom6 months ago
How about SQL joins? &quot;foo JOIN bar ON foo.id = bar.fooid&quot;
评论 #42055680 未加载
xn6 months ago
What about subject–predicate–object triples?