One Line If Statements

Propose new features and changes
User avatar
raron
Posts: 37
Joined: 11 Aug 2014, 00:50

Re: One Line If Statements

04 Sep 2021, 10:05

SandyClams wrote:
01 Sep 2021, 13:04
if you want a one-line if in v2 you can just use a short-circuit expression to do it.

Code: Select all

(DoMsg) && MsgBox(True)
(SkipMessage) || MsgBox(True)
Thanks for the reply.

I have to say I don't think that's more clear though. Where's the "if"? Implied? (I like the ternary operator better then).
Anyway, it is what it is (or I guess, is not; no one-liners). It's just one very unexpected snag to encounter.
eugenesv
Posts: 176
Joined: 21 Dec 2015, 10:11

Re: One Line If Statements

03 Sep 2023, 09:08

Would be nice to have one-liners so that you could nicely align short functions/statements in a tabular fashion
TAC109
Posts: 1125
Joined: 02 Oct 2013, 19:41
Location: New Zealand

Re: One Line If Statements

03 Sep 2023, 17:29

You can already. See for example the ternary operator.

Code: Select all

(A = B) ? C := D : E := F

(A = B) ? C := D : 0        ; True branch only 
Cheers
My scripts:-
XRef - Produces Cross Reference lists for scripts
ReClip - A Text Reformatting and Clip Management utility
ScriptGuard - Protects Compiled Scripts from Decompilation
I also maintain Ahk2Exe
eugenesv
Posts: 176
Joined: 21 Dec 2015, 10:11

Re: One Line If Statements

04 Sep 2023, 00:14

How do you fit a named/hotkey function there? Or a loop? The issues is more universal
(and the extra zero isn't clean)
TAC109
Posts: 1125
Joined: 02 Oct 2013, 19:41
Location: New Zealand

Re: One Line If Statements

04 Sep 2023, 00:59

You asked how to have short one-liners so as to line up in a tabular manner, and what I showed will enable this to be done. Loops etc will need a more traditional approach.

Cheers
My scripts:-
XRef - Produces Cross Reference lists for scripts
ReClip - A Text Reformatting and Clip Management utility
ScriptGuard - Protects Compiled Scripts from Decompilation
I also maintain Ahk2Exe
eugenesv
Posts: 176
Joined: 21 Dec 2015, 10:11

Re: One Line If Statements

04 Sep 2023, 01:07

I also specifically mentioned functions there, so what you showed will actually not enable it
TAC109
Posts: 1125
Joined: 02 Oct 2013, 19:41
Location: New Zealand

Re: One Line If Statements

04 Sep 2023, 02:19

Oh, you can include functions in the condition/true/false parts of the tertiary operator.

Cheers
My scripts:-
XRef - Produces Cross Reference lists for scripts
ReClip - A Text Reformatting and Clip Management utility
ScriptGuard - Protects Compiled Scripts from Decompilation
I also maintain Ahk2Exe
eugenesv
Posts: 176
Joined: 21 Dec 2015, 10:11

Re: One Line If Statements

04 Sep 2023, 02:23

How would you include these functions?

Code: Select all

hk1(ThisHotkey) {SendInput('{Blind}{NumpadDiv}')}
hk2(ThisHotkey) {SendInput('{Blind}{NumpadDiv}')}
hk3(ThisHotkey) {SendInput('{Blind}{NumpadMult}')}
Descolada
Posts: 1172
Joined: 23 Dec 2021, 02:30

Re: One Line If Statements

04 Sep 2023, 02:37

@eugenesv, one-liner functions are already available in v2 as fat arrow functions:
Sum(a, b) => a+b
or from your example
hk1(ThisHotkey) => SendInput('{Blind}{NumpadDiv}')

At one point there comes the question whether a one-liner is worth the terseness over readability and debuggability.

Consider this hotkey:
x::MouseMove(100,100)
I would say this is understandable at a glance: a hotkey which moves the cursor to a specific point. This is quite fine, as is the fat arrow function example above.

What about this one:
x::MouseGetPos(&X, &Y), X=100 && Y=100 ? MouseMove(200, 200) : MouseMove(100, 100)
It is still understandable if one is familiar with multi-statement expressions and ternaries. However I would argue that the following is more readable, easier for other people (especially beginners) to understand, and easier to debug (you can set break-points for the separate lines and then inspect variable contents etc):

Code: Select all

x::
{
    MouseGetPos(&X, &Y)
    if X = 100 and Y = 100
        MouseMove(200, 200)
    else 
        MouseMove(100, 100)
}
This one?
x::Looper:=((n) => --n>0 && (MouseGetPos(&X, &Y), X=100 && Y=100 ? MouseMove(200, 200) : MouseMove(100, 100), Sleep(250), Looper(n-1))), Looper(10)
I would hate to debug that, and understanding it takes considerable effort. I would much prefer

Code: Select all

x::
{
    n := 10
    while --n > 0 {
        MouseGetPos(&X, &Y)
        if X = 100 and Y = 100
            MouseMove(200, 200)
        else 
            MouseMove(100, 100)
        Sleep(250)
    }
}
So the questions is, what are possible common scenarios where you would desire a one-liner loop, where readability would still be okay?
eugenesv
Posts: 176
Joined: 21 Dec 2015, 10:11

Re: One Line If Statements

04 Sep 2023, 04:34

Descolada wrote:
04 Sep 2023, 02:37
@eugenesv, one-liner functions are already available in v2 as fat arrow functions:
Nice, thanks a bunch, wasn't aware of that syntax improvement (was searching the forum for anon functions, but missed these)
Descolada wrote:
04 Sep 2023, 02:37
At one point there comes the question whether a one-liner is worth the terseness over readability and debuggability.
The beauty of tabular alignment that one-liners enable is in this syntax, not in the ternary mess (which is harder to read, words serve a better purpose vs. commas etc)
  • Note that X hotkeys are aligned so it's immediately visible that the key is the same, and the diff in modifiers is also apparent due to them being in the same column
  • then the rest of syntax due to tabular alignment is also very easy to read - you can visually skip repeating statements and only focus on the diffs since there is no horizontal jumps
  • with some flexible tabstop plugin you don't have to maintain many vertical alignments, just place tabs in the right places

Code: Select all

^  x :: {                         MouseMove( 1,  5) }
 ! x :: { MouseGetPos(&X, &Y)
         if	X = 100 and Y = 100	{ MouseMove( 1,  1)
  } else if	X = 200            	{ MouseMove( 2,  2)
  } else if	            Y = 200	{ MouseMove(23, 23)
  } else   	                   	{ MouseMove( 4,  4)
  }
}
But also some short try/catch statemens shouldn't occupy many lines, same for short loops and everything else


And to your loop question: this shouldn't take 3 lines

Code: Select all

loop parse "2345qwertasdfzxcvb" {
    HotKey(pre " & " vk[A_LoopField], hkNumpad←)
  }
lexikos
Posts: 9635
Joined: 30 Sep 2013, 04:07
Contact:

Re: One Line If Statements

04 Sep 2023, 21:00

@eugene
Why shouldn't it take 3 lines?

This doesn't take 3 lines...

Code: Select all

([((n, &v) => n(&v) && MsgBox(v)).Bind(StrSplit("2345qwertasdfzxcvb").__enum(1))*])
eugenesv
Posts: 176
Joined: 21 Dec 2015, 10:11

Re: One Line If Statements

05 Sep 2023, 00:52

It shouldn't take 3 lines because it's a waste of precious vertical space and in case of repeated commands it breaks tabular alignment

I mean, you already have dedicated syntax {}, why does it require newlines?

Your example is unreadable, so that's not the price I'd pay to save 2 lines, I'd like this feature to make my config more readable, not less :)
Descolada
Posts: 1172
Joined: 23 Dec 2021, 02:30

Re: One Line If Statements

05 Sep 2023, 00:55

eugenesv wrote:
04 Sep 2023, 04:34
The beauty of tabular alignment that one-liners enable is in this syntax, not in the ternary mess (which is harder to read, words serve a better purpose vs. commas etc)
Beauty is in the eyes of the beholder I guess, because the example you brought might in this case be easier to comprehend, but gets messy if you try to add something to a specific line (then you'd have to tabulate all the other lines as well) and would probably make the overall code-base less even. Wikipedia has a nice section on the arguments against vertical alignment

But I agree that words are easier to read than cryptic symbols. If one-line if statements were allowed, then perhaps that would be a chance to remove the ternary altogether? I mean if val := if (a > b) then { a } else { b } were allowed then val := a > b ? a : b would be superfluous (as is the case in Rust)...

I think I'd prefer to stick with ternaries, and add guards or something similar:

Code: Select all

val :=
	| a > b => a
	| otherwise => b
And to your loop question: this shouldn't take 3 lines

Code: Select all

loop parse "2345qwertasdfzxcvb" {
    HotKey(pre " & " vk[A_LoopField], hkNumpad←)
  }
You can limit it to two:

Code: Select all

loop parse "2345qwertasdfzxcvb"
    HotKey(pre " & " vk[A_LoopField], hkNumpad←)
Imperative languages such as AHK tend to make more sense when more lines are used, as in this case it's easy to comprehend that one line will be looped some number of iterations. You could adopt a more functional approach instead:
StrSplit("2345qwertasdfzxcvb").ForEach((A_LoopField) => HotKey(pre " & " vk[A_LoopField], hkNumpad←))
Where ForEach is added to Array.Prototype (see example).
eugenesv
Posts: 176
Joined: 21 Dec 2015, 10:11

Re: One Line If Statements

05 Sep 2023, 01:33

Descolada wrote:
05 Sep 2023, 00:55
Beauty is in the eyes of the beholder I guess, because the example you brought might in this case be easier to comprehend, but gets messy if you try to add something to a specific line (then you'd have to tabulate all the other lines as well)
You wouldn't with the flexible tabstop plugin I mentioned (also listed in the wiki), it retabulates a table on changes in any line. Otherwise it'd be a nightmare to do any edits
Descolada wrote:
05 Sep 2023, 00:55
and would probably make the overall code-base less even. Wikipedia has a nice section on the arguments against vertical alignment
Duh, beauty takes effort and tools, though that section misses the point that even when it breaks down you'll get back to the same ugly unaligned space like before! (btw, elastic tabstops in theory can also work with proportional fonts, though that's not been implemented in any popular code editor afaik)
And to your loop question: this shouldn't take 3 lines
You can limit it to two:

Code: Select all

loop parse "2345qwertasdfzxcvb"
    HotKey(pre " & " vk[A_LoopField], hkNumpad←)
This would work with significant whitespace, otherwise it's brittle (what if you add another line later?), so on the contrary I've added {} everywhere to avoid this source of bugs. Unfortunately that extra {syntax} doesn't buy me no newlines
Imperative languages such as AHK tend to make more sense when more lines are used, as in this case it's easy to comprehend that one line will be looped some number of iterations. You could adopt a more functional approach instead:
StrSplit("2345qwertasdfzxcvb").ForEach((A_LoopField) => HotKey(pre " & " vk[A_LoopField], hkNumpad←))
Where ForEach is added to Array.Prototype (see example).
this gives me 'Error: This parameter declaration conflicts with an existing built-in variable.' for A_LoopField. Or do you mean I can only use it with your linked library?
Descolada
Posts: 1172
Joined: 23 Dec 2021, 02:30

Re: One Line If Statements

05 Sep 2023, 01:41

eugenesv wrote:
05 Sep 2023, 01:33
this gives me 'Error: This parameter declaration conflicts with an existing built-in variable.' for A_LoopField. Or do you mean I can only use it with your linked library?
Sorry, I didn't test it, it seems you need to rename A_LoopField to something else then. You don't have to use the linked library, it's fairly simple to define it yourself:

Code: Select all

Array.Prototype.DefineProp("ForEach", {call:_ArrayForEach})
/**
 * Applies a function to each key/value pair in the Array.
 * @param func The callback function with arguments Callback(value[, key, array]).
 * @returns {Array}
 */
_ArrayForEach(this, func) {
    if !HasMethod(func)
        throw ValueError("ForEach: func must be a function", -1)
    for i, v in this
        func(v, i, this)
    return this
}

StrSplit("2345qwertasdfzxcvb").ForEach((val, *) => MsgBox(val "`n")) 
neogna2
Posts: 598
Joined: 15 Sep 2016, 15:44

Re: One Line If Statements

05 Sep 2023, 03:35

Interesting discussions! @eugenesv can you name/link the flexible tabstop plugin? I'd like to try it, to get a feel for the pros/cons in Descolada's wikipedia link.

A way to "onelinerize" if-else if and loop segments is to go for jeeswg's lineseparator symbol idea. DIY: pick your lineseparators, save scripts as .ahkx and set up that custom extension to run a preprocessor script that converts lineseparators, saves the output AutoHotkey code and runs it. For example

loop parse "2345qwertasdfzxcvb" _{HotKey(pre " & " vk[A_LoopField], hkNumpad←)}_
with a preprocessor that does StrReplace(MyCode, "_{", "`n{`n") and StrReplace(MyCode, "}_", "`n}`n").
More complex parsing and conversion needed if the code will ever contain literal strings with the same characters of course.

Similarly " _ " (whitespace-enclosed underscore) and StrReplace(MyCode, " _ ", "`n").

A single underscore currently has no special meaning in AutoHotkey yet is visually distinct and easy to type so is a good candidate if a lineseparator were ever to be officially added.

Built in preprocessing support could use #PreProcess <preprocessor script filepath> where that script contains a function that is called with the current script's source as parameter and returns processed code to execute.
eugenesv wrote:
04 Sep 2023, 04:34
But also some short try/catch statemens shouldn't occupy many lines
Agree, I have wished for Try()
eugenesv
Posts: 176
Joined: 21 Dec 2015, 10:11

Re: One Line If Statements

05 Sep 2023, 05:43

Thank @Descolada, will check it out
neogna2 wrote:
05 Sep 2023, 03:35
Interesting discussions! @eugenesv can you name/link the flexible tabstop plugin? I'd like to try it, to get a feel for the pros/cons in Descolada's wikipedia link.
I'm using this fork with a debouncer as otherwise the plugin is too slow on large tables since it inserts spaces, not just tabs, so it's not a proper implementation (and also breaks on proportional fonts), but then there is no proper implementation of this alignment awesomeness anywhere :(


neogna2 wrote:
05 Sep 2023, 03:35
A way to "onelinerize" if-else if and loop segments is to ... run a preprocessor script
I think if you go down that route of an extra build step, then it should be way more convenient than requiring sprinkles of _ everywhere

Return to “Wish List”

Who is online

Users browsing this forum: sirksel and 11 guests