Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[VxE]'s := guide ? ( to the ternary ) : ( operator ) .


  • Please log in to reply
17 replies to this topic
VxE
  • Moderators
  • 3622 posts
  • Last active: Dec 24 2015 02:21 AM
  • Joined: 07 Oct 2006
What is it?!
The ternary operator is like an If/Else conditional, but packaged to fit inside an expression.

What does it look like?!
The ternary operator looks like a boolean expression followed by a question mark followed by something, then a colon and another something

What is it used for?!
The ternary operator collapses one or more "If/Else" blocks so that they fit inside a normal command or into an expression.

Why bother with it if I can do the same thing with "If/Else"?!
The ternary operator has a coolness factor rating of 14 units = sunglasses. Using it makes your code shorterr, cooler, and more complicated-looking.

Is there an easy way to write them?... I tried once and it I got confused.
Certainly! This is a guide to both writing and understand them...

Firstly: you should start by writing out your code the long Iffy way:
InputBox, answer , Is anybody out there?, What is your name?, , , , , , , , Your Name
If answer < georgf
MsgBox, Your name is stupid.
Else If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
So... you can use the ternary operator to reduce all of those Ifs and Elses and Msgboxes down to a single Msgbox. To begin, comment out the lines that you want to convert and start a new line with the same command that is common to those If/Else blocks. Then put the string % (() ? () : ()) where the argument of interest is (that's pretty simple for a basic Msgbox, but you can use the ternary in whatever argument you want)
InputBox, answer , Is anybody out there?, What is your name?, , , , , , , , Your Name
/*
If answer < georgf
MsgBox, Your name is stupid.
Else If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
*/
MsgBox % (() ? () : ())
OK, now we can start building our ternary expression. Next, find the first boolean expression and paste it into the first set of () parentheses. REMEMBER to use 'expression format' when dealing with literal strings and variables
InputBox, answer , Is anybody out there?, What is your name?, , , , , , , , Your Name
/*
If answer < georgf
MsgBox, Your name is stupid.
Else If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
*/
MsgBox % ((answer < "georgf") ? () : ())
Next, put the contents of the first Block inside the second set of () parentheses.
InputBox, answer , Is anybody out there?, What is your name?, , , , , , , , Your Name
/*
If answer < georgf
MsgBox, Your name is stupid.
Else If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
*/
MsgBox % ((answer < "georgf") ? (MsgBox, Your name is stupid.) : ())
Have you spotted something that's missing and something that should be? Yes, because we are inside an expression, literal strings must be enclosed in "" quote marks and we don't need a second "Msgbox". So fix that and then copy the "Else" block into the third set of () parentheses.
InputBox, answer , Is anybody out there?, What is your name?, , , , , , , , Your Name
/*
If answer < georgf
MsgBox, Your name is stupid.
Else If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
*/
MsgBox % ((answer < "georgf") ? ("Your name is stupid.") : (
If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
))
OMG!! what have we done!! That expression is totally 'F'-ed UP!. Our "Else" block has more than just a single command... it has more "IF/Else"s in it! Have you guessed what we're going to do?... That's right, another ternary operator. Go ahead and paste another happy little (() ? () : ()) onto the line where we're working.
InputBox, answer , Is anybody out there?, What is your name?, , , , , , , , Your Name
/*
If answer < georgf
MsgBox, Your name is stupid.
Else If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
*/
MsgBox % ((answer < "georgf") ? ("Your name is stupid.") : ( (() ? () : ())
If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
))
Have you figured out what do do? Wash, rinse, repeat...
InputBox, answer , Is anybody out there?, What is your name?, , , , , , , , Your Name
/*
If answer < georgf
MsgBox, Your name is stupid.
Else If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
*/
MsgBox % ((answer < "georgf") ? ("Your name is stupid.") : ( ((answer < "normap") ? ("Your name ROCKsORZ!") : (
If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
))
))
...And again...
InputBox, answer , Is anybody out there?, What is your name?, , , , , , , , Your Name
/*
If answer < georgf
MsgBox, Your name is stupid.
Else If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
*/
MsgBox % ((answer < "georgf") ? ("Your name is stupid.") : ( ((answer < "normap") ? ("Your name ROCKsORZ!") : ( (() ? () : ())
If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
))
))
OK, here we are at the last one. We no longer have to nest more ternary operators, so we can go ahead and put the strings into their approprate parentheses
InputBox, answer , Is anybody out there?, What is your name?, , , , , , , , Your Name
/*
If answer < georgf
MsgBox, Your name is stupid.
Else If answer < normap
Msgbox, Your name ROCKsORZ!
Else If answer < tog
Msgbox, Your name is totally wimpy.
Else
MsgBox, Your name is nothing special.
*/
MsgBox % ((answer < "georgf") ? ("Your name is stupid.") : ( ((answer < "normap") ? ("Your name ROCKsORZ!") : ( ((answer < "tog") ? ("Your name is totally wimpy.") : ("Your name is nothing special."))))))
Don't forget to bring those trailing "))" close-parentheses back to the proper line. Now, this expression will work fine, however there is one little thing we can do to make it even shorter. We can bring out the part of each string that is the same ("Your name ") and put it outside of our ternary operator.
InputBox, answer , Is anybody out there?, What is your name?, , , , , , , , Your Name
MsgBox % "Your name " ((answer < "georgf") ? ("is stupid.") : ( ((answer < "normap") ? ("ROCKsORZ!") : ( ((answer < "tog") ? ("is totally wimpy.") : ("is nothing special."))))))
And there you have it! A beautiful decorative hand-carved wooden duck decoy that you made yourself. Hopefully, those who didn't know about this shortcut will have gained a better understanding of how the ternary operator is used in command arguments and how it can be used in expressions.

Feedback welcome! --- [VxE]

Crummy
  • Guests
  • Last active:
  • Joined: --
Hey! Wait a second! My name is not stupid >:(

TodWulff
  • Members
  • 142 posts
  • Last active: Sep 15 2013 04:16 PM
  • Joined: 29 Dec 2007

Why bother with it if I can do the same thing with "If/Else"?!
The ternary operator has a coolness factor rating of 14 units = sunglasses. Using it makes your code shorterr, cooler, and more complicated-looking.

:lol: ROFL! That's good. Thanks for the giggles. Thanks, also, for the nice primer! Take care.

-t

Rhys
  • Members
  • 761 posts
  • Last active: Aug 09 2013 04:53 PM
  • Joined: 17 Apr 2007
I'm very interested if this increases code execution speed over several if/else lines. Thanks for the primer - Very well put together!

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Rhys, in [VxE]'s example, the ternary version is actually slower. Both are under 10µs, though, so it isn't really an issue. Readability is, though... this is one of those cases where ternary makes it less readable.

Generally ternary is more efficient in simple expressions, and less efficient in more complex ones.

Oberon
  • Members
  • 442 posts
  • Last active: Jul 03 2008 11:34 PM
  • Joined: 18 Feb 2008
In higher level languages like C# and PHP I usually use associative arrays for lookup tables and switch/case as an alternative to stacking If statements. Ternary operators shouldn't be nested more than three times deep, and if it has to be this much for numerical values only. Ifs are faster because machine code processes them in the same form, giving the compiler more room to optimize.

Nice article by the way. As a hobbyist programmer there are many gaps in my knowledge so I always find it interesting to read stuff like this.

BoBo¨
  • Guests
  • Last active:
  • Joined: --
Cool [HowTo]. Thx. :D
I'd like to see something similar for 'continuation sections'. *wishgrin*

Especially when we'll set up real loooooooooong lines, like those shown above, it would make sense to use the continuation option to get a better layout/visability, right?

I saw it sometimes used with DllCall()s ... 8)

VxE
  • Moderators
  • 3622 posts
  • Last active: Dec 24 2015 02:21 AM
  • Joined: 07 Oct 2006
Thx for the feedback everyone :D I thought of something that would improve this guide but that I probably would mess up if I did it myself:

Examples of commonly seen ternary usages !

I would like to keep a growing list of instances where the ternary operator is preferred for readability. For example:
[color=violet]Hotkey[/color]:: SetTimer, [color=brown]Label[/color], % [color=red](([/color]Bool := !Bool[color=red]) ? ([/color][color=blue]Number[/color][color=red]) : ([/color][color=green]"Off"[/color][color=red]))[/color]

Maybe some more examples like this with brief explanations would help new users learn from more examples, and would improve the search-hit-keyword spread for this thread.

poetbox
  • Members
  • 113 posts
  • Last active: Sep 11 2013 08:05 AM
  • Joined: 07 Jan 2007

btw: I'm invoking

...Post helpful tips and tricks.

to post this here. {also this is my 500th post.}

Well Done! :O :lol: :D :)

  • Guests
  • Last active:
  • Joined: --
Hotkey:: SetTimer, Label, % ((Bool := !Bool) ? (Number) : ("Off"))

I tried decrypting this

isn't this the same since Number as a var isnt filled ?

Hotkey:: SetTimer, Label, % ((Bool := !Bool) ? () : ("Off"))

Why use the word Bool, I can use for example just a n or any var right ?
Hotkey:: SetTimer, Label, % ((n := !n) ? () : ("Off"))


Decrypting the whole expression would be ?
;Hotkey:: SetTimer, Label, % ((Bool := !Bool) ? (Number) : ("Off"))

Hotkey::
{
If Bool := !Bool
SetTimer, Label, %Number&
else
SetTimer, Label, off
}
Return



Is this all correct ?

trik
  • Members
  • 1317 posts
  • Last active: Jun 11 2010 11:48 PM
  • Joined: 15 Jul 2007
Hotkey::

SetTimer, Label, % !Bool ? Number : "Off"

Religion is false. >_>

VxE
  • Moderators
  • 3622 posts
  • Last active: Dec 24 2015 02:21 AM
  • Joined: 07 Oct 2006

[color=violet]Hotkey[/color]:: SetTimer, [color=brown]Label[/color], % [color=red](([/color]Bool := !Bool[color=red]) ? ([/color][color=blue]Number[/color][color=red]) : ([/color][color=green]"Off"[/color][color=red]))[/color]

This isn't meant to be literal code. The words are meant to stand in place of their specified type or class, or variable containing same (the exceptions being "off" which is meant to be literal, and 'SetTimer', which is a command)

Hence, the expanded illustration (and fully working example) would be
; [color=violet]Hotkey[/color]:: SetTimer, [color=brown]Label[/color], % [color=red](([/color]Bool := !Bool[color=red]) ? ([/color][color=blue]Number[/color][color=red]) : ([/color][color=green]"Off"[/color][color=red]))[/color]

; using left-ctrl + a will do exactly the same thing as right-ctrl + a, despite using different code
>^a::SetTimer, Ctrl_A_Label, % (Ctrl_A_Toggle := !Ctrl_A_Toggle) ? 1000 : "off"

<^a:: ; this is a [color=violet]Hotkey[/color]
If (Ctrl_A_Toggle := !Ctrl_A_Toggle) ; use () to indicate an expression in which a variable is assigned the value of its boolean negation
   SetTimer, Ctrl_A_Label, 1000 ; '1000' is [color=blue]Number[/color] in this case, but it could just as easily be a %variable%
Else
   SetTimer, Ctrl_A_Label, [color=green]Off[/color]
Return ; because a multi-line hotkey-subroutine needs this

Ctrl_A_Label: ; this is a label
Tooltip Update position once a second
return


TLM
  • Administrators
  • 3864 posts
  • Last active:
  • Joined: 21 Aug 2006
Great info that I had to bump. This thread is god mode!

Thanks

Posted Image

don't duplicate, iterate!


hd0202
  • Members
  • 709 posts
  • Last active: Feb 14 2016 08:05 PM
  • Joined: 13 Aug 2006
If you write it in another form, I think it is very good readable. How many lines would the following example use with if/else?
sub := (command1 = "#a") ? "add"
	     : (command1 = "#b") ? "build"
	     : (command1 = "#c") ? "change"
	     : (command1 = "#d") ? "down"
	     : (command1 = "#e") ? "unten"
	     : (command1 = "#f") ? "find"
	     : (command1 = "#i") ? "info"
	     : (command1 = "#j") ? "join"
	     : (command1 = "#k") ? "kill"
	     : (command1 = "#l") ? "locate"
	     : (command1 = "#m") ? "move"
	     : (command1 = "#o") ? "output"
	     : (command1 = "#p") ? "tabulator"
	     : (command1 = "#q") ? "tasten"
	     : (command1 = "#r") ? "restore"
	     : (command1 = "#s") ? "substitute"
	     : (command1 = "#t") ? "text"
	     : (command1 = "#u") ? "up"
	     : (command1 = "#w") ? "woerterbuch"
	     : (command1 = "#x") ? "exit"
	     : (command1 = "#z") ? "zeile"
	     : (command1 = "#1") ? "oben"
	     : (command1 = "#ß") ? "datein"
	     : (command1 = "#<") ? "fragen"
	     : (command1 = "#v") ? "listv"
	     : (command1 = "#?") ? "debuggen"
	     : "falsch"
	gosub %sub%

Hubert

sinkfaze
  • Moderators
  • 6367 posts
  • Last active: Nov 30 2018 08:50 PM
  • Joined: 18 Mar 2008
Since I think this guide is highly underrated in its usefulness to many AHK'ers out there, I thought I'd post an example of using ternary from a script collaboration I'm working on. We're working on making a GUI with tabs but on only one of the tabs we want to be able to toggle the window size to create a pseudo-"rolled up" window effect.

In terms of "normal" AHK coding I'd need to write something like this to check which tab is active first then check the window's size to determine which state to toggle to:

if CurrentTab=1
{
  if GuiHeight=572
     WinMove, %WinTitle%, , , , , 278 
  else
     WinMove, %WinTitle%, , , , , 572 
}
else
  return

But ternary condenses the whole thing down to one line:

WinMove, %WinTitle%, , , , , % CurrentTab=1 ? (GuiHeight=572 ? 278 : 572) : ""