if var in/contains comma-separated list/array

Discuss the future of the AutoHotkey language
User avatar
jeeswg
Posts: 5428
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

23 Sep 2018, 06:50

- This is the one important AHK v2 issue I've seen without an easy solution.
- These are my 2 best solutions at present, please be mature about any feedback.
- If you specify 1 needle for contains/in, it should be relatively easy to add a 2nd needle without rewriting everything.

Code: Select all

;IDEA 1: xxxC/xxxP operators

if (var contains StrSplit("abc,def,ghi", ",")) ;we need *SOMETHING* better than this
if (var contains "item1,item1ctd,item1ctd") ;1 item
if (var containsC "item1,item2,item3") ;3 items (no special ',,' handling)
if (var containsP "item1|item2|item3") ;3 items (no special '||' handling)

;contains, containsC, containsP
;in, inC, inP
;starts, startsC, startsP ;potentially
;ends, endsC, endsP ;potentially

;note: the xxxP operators are useful for needles that contain commas and for conversion to/from ~= (RegExMatch)

;==================================================

;IDEA 2: StrSplit comma/pipe unary operators

if (var contains StrSplit("abc,def,ghi", ",")) ;we need *SOMETHING* better than this
if (var contains "item1,item1ctd,item1ctd") ;1 item
if (var contains splitc "item1,item2,item3") ;3 items (no special ',,' handling)
if (var contains splitp "item1|item2|item3") ;3 items (no special '||' handling)

;note: perhaps a 'split' or 'splitx' operator would split every character (n-length string to n-length array)

;note: alternatively/additionally, a binary operator: "a,b,c" split "," [although this puts the operator after the string, where it's less visible, and easy to miss]
;[EDIT:] if (var contains "abc,def,ghi" split ",") [not great, less clear than StrSplit()]
Last edited by jeeswg on 23 Sep 2018, 10:49, edited 1 time in total.
guest3456
Posts: 2468
Joined: 09 Oct 2013, 10:31

Re: if var in/contains comma-separated list/array

23 Sep 2018, 10:36

there are function and regex alternatives in this thread:

https://autohotkey.com/boards/viewtopic ... 37&t=23033

using a C/P suffix is awful

User avatar
jeeswg
Posts: 5428
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

23 Sep 2018, 10:45

- Thanks for your response.
- I'd want something built-in, so that scripts can be easily shared. So no custom functions.
- RegEx is slow. (Although is StrSplit slower? I'll do some benchmark tests.)
- RegEx requires character escaping.
- RegEx requires fiddly ^, $ and parenthesis adding.
- RegEx handles string comparisons only. The 'in' operator might support handling for numeric comparisons.
- So StrSplit is the best existing option.

- I would really appreciate if people think about this problem, and try to come up with any syntax suggestions. I do find this question a tricky one.
- Another idea would be something like: var match "X,)abc,def,ghi". That would check for an exact match, comma-delimited. A kind of home-grown simpler RegEx for C/E/S/X (contains/ends/starts/exact).
guest3456
Posts: 2468
Joined: 09 Oct 2013, 10:31

Re: if var in/contains comma-separated list/array

23 Sep 2018, 18:15

jeeswg wrote: - I'd want something built-in
then there is nothing to talk about. either build it in yourself and submit a pullrequest, or wait for lexikos to build it in
jeeswg wrote:so that scripts can be easily shared. So no custom functions.
just include your custom function in the script and it can be easily shared.

User avatar
jeeswg
Posts: 5428
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

23 Sep 2018, 19:21

- The point of this forum is to *talk about* *built-in* functionality.
- We don't have a consensus here, so no pull requests from me.
- Like with the command/function syntax 6-year debate, people here have complained but offered nothing, delaying a decision.
- FWIW I'd say: string = 1 item, array = multiple items, that's enough for a working operator. I await ideas on haystack arrays and delimiter-separated lists.

- Re. 'easily shared'. Ideally, basic functionality should be newbie-friendly. So, no duplicate function errors, or differing functions with the same name, or 10 versions of the same function.
User avatar
kczx3
Posts: 692
Joined: 06 Oct 2015, 21:39

Re: if var in/contains comma-separated list/array

23 Sep 2018, 19:39

I’d rather a method on the string and object prototypes like JavaScript than using a keyword anyways
User avatar
jeeswg
Posts: 5428
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

23 Sep 2018, 19:52

Interesting point. I was trying so hard to come up with a good idea, I even thought of using an operator together with a method on a string:
if var contains "abc,def,ghi".split(",")
iseahound
Posts: 355
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: if var in/contains comma-separated list/array

24 Sep 2018, 20:03

Sorry, what's wrong with if var contains "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
which is parsed as if var.contains("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")

As I understand it, contains is a function which takes any number of variables. (variadic)
and contains is a method of var.

Caveats:
Another example: Say I have the following in my code:

Code: Select all

if(foo contains bar) { ..
Say, I need to negate the condition. If I modify it as follows:

Code: Select all

if(!foo contains bar) { ..
Bummer. This gets parsed as (!foo).contains(bar). Not what we wanted.

Or suppose you need to add a new condition in addition, and you modify it so:

Code: Select all

if(foo contains bar && cond) { ..
Another bummer. This gets parsed asfoo.contains(bar.&&(cond)). Not what we wanted, again.

Of course, you could add a bunch of parentheses around, but that would be ugly and hard to read/edit as compared with dot notation.

Now, all of what I said above applies to symbolic method names too. However symbolic methods look unnatural when used with dot syntax, and so I prefer the infix syntax for them.
Source: https://stackoverflow.com/questions/102 ... t-notation
User avatar
nnnik
Posts: 3527
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: if var in/contains comma-separated list/array

25 Sep 2018, 01:24

I don't want to add special features for comma separated lists. No argument you have to offer can change my mind about this.

@iseahound
Sadly our "," already has a specific meaning so this Form of calling won't be possible. Also contains is an operator rather than a method call.
Recommends AHK Studio
lexikos
Posts: 6207
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: if var in/contains comma-separated list/array

25 Sep 2018, 06:29

"not in" and "not contains" are a possibility. Python has "is not".
iseahound
Posts: 355
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: if var in/contains comma-separated list/array

25 Sep 2018, 10:42

nnnik wrote:Also contains is an operator rather than a method call.
There is an equivalence between operators and methods.

Code: Select all

2 + 3
2.+(3) ; strange but should be valid
which seems strange. But consider this code:

Code: Select all

object.push("dog", "cat")
object push "dog", "cat"
which should be command syntax for object methods.

To parse everything correctly:

Code: Select all

obj push "dog", "cat"
obj(push("dog", "cat")) ; obj is not a function and does not take arguments. 
obj.push("dog", "cat") ; try invoking a method of obj. 
So this is the sort of radical change I'd like to see in v2. It would do 3 main things.
- Settle the Command vs. Function syntax argument once and for all by allowing both commands and functions to have the same expressiveness.
- Formalize operators like contains, such that operators are in some sense global methods, and object methods are by default limited to that object
- Allow operator overriding.

I took inspiration from here: https://docs.scala-lang.org/style/metho ... ation.html

EDIT: I made a separate thread https://autohotkey.com/boards/viewtopic ... 37&t=56294
User avatar
nnnik
Posts: 3527
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: if var in/contains comma-separated list/array

25 Sep 2018, 11:24

operators are not methods in AHK. And Strings cannot have string specific methods yet.
Recommends AHK Studio
iseahound
Posts: 355
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: if var in/contains comma-separated list/array

25 Sep 2018, 11:30

There exists a duality between operators and methods.

See operator overriding in Python: https://thepythonguru.com/python-operator-overloading/
which is a bit of a mess, since they define __add__ to be a meta function to represent +
User avatar
nnnik
Posts: 3527
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: if var in/contains comma-separated list/array

25 Sep 2018, 12:16

The possibility exists. But not in AHK - at least not yet.
Recommends AHK Studio
iseahound
Posts: 355
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: if var in/contains comma-separated list/array

25 Sep 2018, 17:07

Hopefully soon
User avatar
nnnik
Posts: 3527
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: if var in/contains comma-separated list/array

25 Sep 2018, 17:35

I doubt that will happen in v2.
Recommends AHK Studio
User avatar
jeeswg
Posts: 5428
Joined: 19 Dec 2016, 01:58
Location: UK

Re: if var in/contains comma-separated list/array

04 Nov 2018, 21:50

Anyhow, methods applied to strings are already possible.

Code: Select all

;Objects
;https://hotkeyit.github.io/v2/docs/Objects.htm
;When a non-object value is used with object syntax, the default base object is invoked. This can be used for debugging or to globally define object-like behaviour for strings, numbers and/or variables. The default base may be accessed by using .base with any non-object value; for instance, "".base. Although the default base cannot be set as in "".base := Object(), the default base may itself have a base as in "".base.base := Object().

q:: ;methods applied to strings
"".base.base := {len:"StrLen", split:"StrSplit"}

vOutput := ""
for vKey, vValue in "a,b,c".split(",")
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput

vText := "a,b,c"
vOutput := ""
for vKey, vValue in vText.split(",")
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput

vText := "abcdefghijklmnopqrstuvwxyz"
MsgBox, % vText.len()
MsgBox, % "abcdefghijklmnopqrstuvwxyz".len()
return
iseahound
Posts: 355
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: if var in/contains comma-separated list/array

15 Nov 2018, 22:33

Yeah that's why I liked my suggestion of making things methods operators.

Code: Select all

; Define a method that works on the String class.
"".base.contains := Func("Contains")

Contains(state, terms*) {      ; state means internal state. In an AHK object, it would be called "this", and is implicit (does not need to be the 1st parameter).
   for index, word in terms    ; terms contains our comma separated values (CSV).
      if (state ~= word)       ; ~= is short hand for RegExMatch().
         return word           ; return the matching word instead of a Boolean (true).
}

MsgBox % "Jumpy zebra vows to quit thinking coldly of sex.".contains("zebra")
MsgBox % "Jumpy zebra vows to quit thinking coldly of sex.".contains("deer", "cobra", "lion")
It wouldn't do anything to the code other than changing how it is parsed. I wish the following would work:

Code: Select all

MsgBox % "Jumpy zebra vows to quit thinking coldly of sex." contains ("zebra")
which looks nicer in an if statement

Code: Select all

if ("Jumpy zebra vows to quit thinking coldly of sex." contains ("zebra"))
   return true
we could even even have a rule where if there is only one argument, the parenthesis could be omitted:

Code: Select all

if ("Jumpy zebra vows to quit thinking coldly of sex." contains "zebra")
   return true
if ("Jumpy zebra vows to quit thinking coldly of sex." contains ("deer", "cobra", "lion")) ; Multiple arguments in parenthesis!!!!
   return true
There is the idea of prefix, infix, and postfix notation in some languages. Haskell? If you have a simple function such as Add(x, y), you could remove the parenthesis first. This resembles command syntax in AHK v2. Add x, y Now this is called prefix notation because the function is before the arguments. Infix notation would be x add y. This is more natural if the function is symbolic like x + y. However, in Haskell, the function name can only be placed between the first and second arguments. So Add x, y, z could potentially become x Add y z. I think this is confusing so I would recommend that we keep the AHK way of comma separation and force multiple arguments to be wrapped in parenthesis and comma separated like x Add (y, z). I think this is how Scala does this.

Return to “AutoHotkey v2 Development”

Who is online

Users browsing this forum: No registered users and 4 guests