Map CaseSense

Discuss the future of the AutoHotkey language
User avatar
kczx3
Posts: 1119
Joined: 06 Oct 2015, 21:39

Map CaseSense

27 May 2020, 07:05

Am I reading correctly that there is no way to initialize a non-case sensitive Map in a single line? The docs state that you can’t set the CaseSense property on a non-empty Map. Thus, one would have to initialize a new Map, set the property, and then fill the Map one by one. Just making sure I understand correctly.
Helgef
Posts: 4450
Joined: 17 Jul 2016, 01:02
Contact:

Re: Map CaseSense

27 May 2020, 08:25

That is correct. One possibility is to interpret the first parameter of map() as a casesense setting, either always or only when there is an odd number of parameters, or just map.add(p*).
Edit, add could be useful regardless I suppose.
Cheers.
User avatar
kczx3
Posts: 1119
Joined: 06 Oct 2015, 21:39

Re: Map CaseSense

27 May 2020, 08:35

Great, thanks for confirming my interpretations. I do think it would be convenient to be able to specify the case sense during construction, especially since it is basically a property that can't be changed once set (once the Map has a count > 0).
User avatar
nnnik
Posts: 4468
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Map CaseSense

28 May 2020, 01:57

Or just make 2 map types (case sensitive and case insensitive map)
Recommends AHK Studio
lexikos
Posts: 6975
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Map CaseSense

29 May 2020, 18:07

For my first use, I was already using a new Map type, and had no need to populate it at construction time.

Code: Select all

class PermissiveMap extends Map {   ; Make old code work more easily.
    CaseSense := "Off"
    __item[key] {
        get {
            try
                return base[key]
            catch
                return ""
        }
    }
}
Map didn't have this option when I first released it because I couldn't decide on syntax; all of my ideas, including this one, were unappealing for one reason or another. However, it's a lot easier to work around the lack of a convenient constructor function (by defining one!) than it is to work around the lack of a native case-insensitive Map (without introducing bugs).

One idea (or multiple ideas?) I had was first to extend [] for literal maps by simply adding ::

Code: Select all

colours := [
  "red": 0xff0000,
  "green": 0x00ff00,
  "blue": 0x0000ff
]
Then to allow an empty map, [:].

A further extension of that could be [:i] for options (I probably had been dealing with RegEx that day):

Code: Select all

colours := [:i  ; Case-insensitive
  "red": 0xff0000,
  "green": 0x00ff00,
  "blue": 0x0000ff
]
I think Map("Off") would be too obscure. Another idea I had before adding the property was to use a unique object as a reserved key, perhaps only for the function: Map(Map.Opt, "i"). I don't remember whether I had any other options (aside from "locale") in mind. Maybe something controlling type coercion (which can already be done easily enough by overloading __item).

Older ideas were simple functions like imap() or mapi() (both of which unfortunately coincide with tech acronyms), and
Keeping the operator may enable further syntax extensions, such as new Collection {Prop: 4, [1]: "first"} to specify property and array element values. Collection.new({...}) would not work for this if the standard object created by {} has no indexing capability (no array/associative array content).
... which would need to be updated since I chose not to keep the new operator. After transcribing the idea, I realized it could be more general: res := obj {p1: v1, p2: v2} -> res := (obj.p1 := v1, obj.p2 := v2, obj).

After finding how easy it was to lex scripts and adjust to changes in the language with LPeg (for Scintillua), I figured tools based on similar techniques would be very useful for prototyping new language features, or even implementing them (where use of user-defined features might drive language development). I'm reluctant to experiment with new syntax directly.

Anyway, non-essential syntax sugar can wait until after v2.0.
HotKeyIt
Posts: 2135
Joined: 29 Sep 2013, 18:35
Contact:

Re: Map CaseSense

01 Jun 2020, 13:57

[:] +1
That would be great, I think.
Helgef
Posts: 4450
Joined: 17 Jul 2016, 01:02
Contact:

Re: Map CaseSense

05 Jun 2020, 12:20

lexikos wrote:I think Map("Off") would be too obscure.
I agree, and likewise, I think inStr(x,y, 'Off') is too obscure. It would be much clearer if we used built in constants, eg, Map(Case_Insensitive) and inStr(x,y, Case_Insensitive).

Anyways, I think aMap.CaseSense := whatever is pretty clear. One possible solution is to defer the sorting until a key/value is requested, implementing this more generally, so that inserting never sorts, could have positive impact on performance. I suppose that is quite a bit if work though. I suggest we allow changing the property for a non-empty map and just qsort it. If we want to implement defered sort later there are no compatibility issues.
nnnik wrote:Or just make 2 map types (case sensitive and case insensitive map)
It is a good idea. We can keep map() as it, is but make it case insensitive (no case options) and add a hashMap() (case sensitive, no options).

Cheers-
lexikos
Posts: 6975
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Map CaseSense

06 Jun 2020, 03:58

If you are changing CaseSense, strings that were unique before might suddenly have duplicates. It's easy to remove them during the sort process, but is that really a valid response to assigning CaseSense? This is a can of worms I see no need to open. CaseSense could safely be changed under certain simple conditions, such as if there's no more than 1 string key (and keys of other type), but it seemed like needless complication, so I saved a few bytes by prohibiting any changes when Count != 0.

Allowing CaseSense to be changed after adding the items doesn't particularly make it convenient. I would still be defining a class or function and using that instead (if I wasn't just inserting one at a time).
I wrote:Older ideas were simple functions like imap() or mapi() (both of which unfortunately coincide with tech acronyms),
... and classes. The implementation of CaseSense is simple. I considered creating a second class based on the same underlying code instead of - or in addition to CaseSense - but didn't because: 1) locale mode, 2) I didn't like any of the possible names, 3) implementing (just) the property was simpler (and means smaller binary code), 4) there is always the possibility of doing it later.

There is nothing about the name "hashMap" that says it must be case-sensitive or that "map" is not. Unless the implementation of the map is integral to how or why it is used, and that implementation is a hash table, I will not use this word in the name. Also, I think it's a very programmer-centric term, oriented on the specific data structure rather than the concept of associating keys with values.

I've long held the thought that I should do some testing with a hash map implementation (to compare code size and performance), but realistically I'll probably never bother.
It would be much clearer if we used built in constants, eg, Map(Case_Insensitive) and inStr(x,y, Case_Insensitive).
I think these things would be better with typed enums, which would convert to the appropriate strings (useful for debugging), wouldn't require quoting, and wouldn't require parsing at runtime (but could be if needed). But that's one of the ideas I've decided not to pursue until after v2.0.

Return to “AutoHotkey v2 Development”

Who is online

Users browsing this forum: No registered users and 6 guests