Page 2 of 4

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

Posted: 23 Sep 2018, 06:50
by jeeswg
- 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()]

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

Posted: 23 Sep 2018, 10:36
by guest3456
there are function and regex alternatives in this thread:

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

using a C/P suffix is awful

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

Posted: 23 Sep 2018, 10:45
by jeeswg
- 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).

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

Posted: 23 Sep 2018, 18:15
by guest3456
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.

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

Posted: 23 Sep 2018, 19:21
by jeeswg
- 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.

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

Posted: 23 Sep 2018, 19:39
by kczx3
I’d rather a method on the string and object prototypes like JavaScript than using a keyword anyways

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

Posted: 23 Sep 2018, 19:52
by jeeswg
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(",")

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

Posted: 24 Sep 2018, 20:03
by iseahound
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

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

Posted: 25 Sep 2018, 01:24
by nnnik
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.

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

Posted: 25 Sep 2018, 06:29
by lexikos
"not in" and "not contains" are a possibility. Python has "is not".

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

Posted: 25 Sep 2018, 10:42
by iseahound
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

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

Posted: 25 Sep 2018, 11:24
by nnnik
operators are not methods in AHK. And Strings cannot have string specific methods yet.

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

Posted: 25 Sep 2018, 11:30
by iseahound
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 +

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

Posted: 25 Sep 2018, 12:16
by nnnik
The possibility exists. But not in AHK - at least not yet.

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

Posted: 25 Sep 2018, 17:07
by iseahound
Hopefully soon

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

Posted: 25 Sep 2018, 17:35
by nnnik
I doubt that will happen in v2.

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

Posted: 04 Nov 2018, 21:50
by jeeswg
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

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

Posted: 15 Nov 2018, 22:33
by iseahound
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.

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

Posted: 22 Apr 2019, 11:29
by jeeswg
The issue of how to handle a comma-separated list is back.
This time for InputHook's MatchList parameter:
"abc,def,ghi" [currently 3 items, not 1 item]
",," [currently a literal comma, not 3 blank items, not 1 item]

Test build - InputHook, long paths, switch-case - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=24&t=63861
Input - Syntax & Usage | AutoHotkey
https://autohotkey.com/docs/commands/InputHook.htm#comparison

I have no particular desire to debate this any further, however, if you want to say something re. Input/InputHook/in/contains, and how literal strings are handled, you'd better say it now, before it becomes set in stone for AHK v2.
If pushed, I'd have to say: a literal string should always be treated as one item. But, having to use arrays for multiple items introduces verbosity, and so there's no easy answer.

Are there other places where comma-separated lists are present in AHK?

[EDIT:] For reference, Explorer's SortColumns property uses a semicolon-separated list, so, delimiter-separated lists are not unheard of.
jeeswg's Explorer tutorial - AutoHotkey Community
https://www.autohotkey.com/boards/viewtopic.php?f=7&t=31755

[EDIT:] At this point, I'm not so bothered how in/contains will handle strings, be it string = 1 item (consistency), or string = comma-separated list (convenience), I'll trust the devs to make the decision.

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

Posted: 27 Oct 2019, 12:35
by jeeswg
To move on, I'd say: 1 string is always 1 item. And if you want 1 string treated as a comma-separated list, you can write your own function, like so:

Code: Select all

if var contains "abc,def,ghi" ;1 literal string

if var contains ["abc", "def", "ghi"] ;3 strings

if MyContainsCSL(var, "abc,def,ghi") ;3 strings

MyContainsCSL(var, list)
{
	if IsObject(list)
		return (var contains list)
	return (var contains StrSplit(list, ","))
}
Potentially a built-in StrContains function could accept 'D,' to have a comma-separated list, but for the foreseeable future I'd be happy with the above.
(The same principles would apply to 'in', MyInCSL/MyEqualsCSL and a potential StrEquals function.)

(I know that = and 'in' would be similar, however, 'in' could be made case sensitive.)
(I know that InStr and 'contains' would be similar, however, it's often convenient to write all statements in an if/else ladder consistently, using either a function or an operator.)