Page 2 of 4
Re: Map shorthand
Posted: 23 Aug 2019, 18:26
by jeeswg
- I suppose it boils down to: should {} be used for properties or keys. I'm neutral.
- lexikos gave good reasons for it being properties; and converting old scripts to use Map() instead of {} has been pretty easy.
- My one query would be, when doing JSON definitions in other languages, is that typically to create properties, or to create keys? (Although even if it is keys, properties for {} still might be OK/better.)
JSON Example
https://json.org/example.html
- Another consideration would be some mode where keys and properties are equivalent, to replicate partially or fully the AHK v1 behaviour. I.e. you define the object, and then use a one-liner to apply the mode.
Re: Map shorthand
Posted: 23 Aug 2019, 21:32
by lexikos
Code: Select all
return {x: left, y: top, w: right-left, h: bottom-top}
This is an ad-hoc object. There is no good reason to use a Map for this. There are good reasons not to: semantics (these are properties, not array elements), case-sensitivity and access syntax (which reflects semantics).
nnnik wrote:I never create objects ad-hoc with known properties.
I don't believe it, but putting that aside;
Do you regularly create associative arrays and need to populate them with a fixed list of key-value pairs at the point of creation?
If I know that a given key or name will be used
and it needs an initial value when the object is created, there is probably always something setting it apart from every other key-value pair. In other words, it's a property or attribute of the collection, not an item within the collection. There are bound to be
exceptions, but for those we don't need shorthand syntax.
The main purpose of separating array elements from properties is to prevent the kind of conflicts that occur when keys
are not known in advance, such as words like "delete", "count" or "base" coming from a document (or script) or other external source.
Re: Map shorthand
Posted: 24 Aug 2019, 22:32
by nnnik
I mostly create classes for stuff like that.
I really mainly use the shorthand syntax for lookup tables
Re: Map shorthand
Posted: 24 Aug 2019, 23:02
by jeeswg
- I agree with both of those sentences.
- In my newly converted main scripts/libs:
- Every time I use Map, it's for a blank map, or a lookup table.
- The half-dozen times I use {} to create an object, the object is empty initially, and I add in the properties one by one. Only twice did I create a one-line ad-hoc object, but separating the property assignments, might be better:
Code: Select all
oTL := {x:(vIndexX<0)?0:vIndexX,y:(vIndexY<0)?0:vIndexY}
oBR := {x:(vIndexX>vImgW)?vImgW:vIndexX,y:(vIndexY>vImgH)?vImgH:vIndexY}
oTL := {}
oTL.x := (vIndexX<0) ? 0 : vIndexX
oTL.y := (vIndexY<0) ? 0 : vIndexY
oBR := {}
oBR.x := (vIndexX>vImgW) ? vImgW : vIndexX
oBR.y := (vIndexY>vImgH) ? vImgH : vIndexY
- For classes, I usually use class definitions, only twice did I create a class as an ad-hoc object, in order to change the array's/map's default value:
Code: Select all
;AHK v1 only:
oMap := {base:{__Get:Func("Abs").Bind(0)}}
oArray := {base:{__Get:Func("Abs").Bind(0)}}
- I wouldn't find it confusing if 'key' in {key:value} didn't use quotes cf. 'key' in obj["key"] := value.
- So on that basis, {} would be more useful as an alias for Map() than for Object().
Re: Map shorthand
Posted: 25 Aug 2019, 03:12
by swagfag
ok, so what i gather from this is use
Map when:
- u care about key case-sensitivity
- u want objects as keys
- u need a key called base
in any other case continue using objects, business as usual
i was under the impression that
Map was meant to supersede this very usage, and
Object()'s purpose would then be solely to act as a base to inherit from/attach properties AND methods to
but i guess not
Re: Map shorthand
Posted: 19 Oct 2019, 20:20
by lexikos
fincs wrote: ↑19 Oct 2019, 17:44
[...] I still think that
{ ... } not yielding anything other than a Map is misleading, since this is JSON-like syntax (and amusingly, JSON mandates quoted strings for keys which reinforces this view). If any of the Map shorthand proposals goes through, we would have three literal object syntaxes: one for arrays, one for maps and one for object. While I don't necessarily disagree here with the current design and I do think it makes sense to have a flexible type that provides the backbone for properties (and methods); I suspect maps vs objects might be a superficial source of confusion for inexperienced users (the fact that they have different syntax definitely helps though). We might see some users compelled to abuse objects as if they were a different way to achieve the same end result provided by maps.
I agree that anyone familiar with JSON
could be confused, but I use object literals far more often than I would use non-empty map literals.
{} is almost always used with literal names, which make no sense for a map. I am willing to consider suggestions for alternative syntax (for objects and maps).
On the other hand, JavaScript uses
{} for objects,
not maps, which don't really have first-class syntax support.
If any part of the syntax resembles JavaScript, JavaScript users (uneducated in the ways of AutoHotkey) are likely to be confused since objects do not work the same way.
As for "abusing" objects as maps, they'd have to use
obj.%key%, which is not as obvious as
obj[key]. Using an object to group a set of known attributes (properties) or related variables is not abuse. As I've explained before, (putting aside non-string keys) map is primarily for cases where keys are not known in advance and could conflict with properties.
If the keys are not known in advance, they are not going to be hard-coded. The syntax for accessing map elements is optimized for this, whereas the syntax for accessing properties is optimized for hard-coded names. Names in AutoHotkey are case-insensitive, therefore property names are case-insensitive. Map keys can be arbitrary (and normalizing case is easy), therefore map keys are case-sensitive. (However, I intend to add a case-insensitive mode or type.)
@swagfag
It doesn't seem like you read and/or understand my previous post.
Re: Map shorthand
Posted: 20 Oct 2019, 13:24
by swagfag
@lexikos u are mistaken on both counts
having gone through all my production scripts i can safely conclude that the only reason why ud ever want to use a Map is if u needed the keys to be case-sensitive. The other far unlikelier reason is if u had a key called "base". The fact that u can also have properties about the collection isnt reason enough(without too much effort u can also separate a bunch of properties about an object from the rest of the used-to-be-properties-but-have-now-become-keys)
only on one occasion did i have to switch to a Map and in that case it was purely because of case-sensitivity - replacing an instance of scripting.dictionary
the remaining associative arrays ive left as objects. forloop iteration is a bit hamfisted, having to call .OwnProps() every time. so is lookup with .%var%, but anyway i can probably live with that
i guess Maps arent gonna see as much usage as once originally thought, at least not enough to warrant introducing special syntax
Re: Map shorthand
Posted: 21 Oct 2019, 00:55
by nnnik
You could also just use maps everytime and not have to worry if you coincidentially hit one of the magic object names.
Re: Map shorthand
Posted: 21 Oct 2019, 02:23
by swagfag
still an imperfect solution and one not without downsides, access now becomes more complicated/tiresome, u have to make sure the case matches or StrLower everything beforehand, pair semantics are lost on Map's constructor(i guess u can newline but meh)
Re: Map shorthand
Posted: 21 Oct 2019, 04:03
by lexikos
You cannot know which words or strings might be used in every other script, or sometimes even your own. If "base", "__Item" or any custom property names are
rarely used, that means that on rare occasions, scripts
will misbehave. The example I gave was actually a real one that I have encountered multiple times.
such as words like "delete", "count" or "base" coming from a document (or script) or other external source.
If you were to misuse an object's properties to index the words in some object-based scripts, the documentation, this page, or an English dictionary, it is
very likely that there will be a conflict.
I intend to add a case-insensitive type or mode soon, although it is trivial to implement a basic case-insensitive map using the case-sensitive map.
Code: Select all
m := MapI.new()
m["base"] := 10
MsgBox m["BASE"]
class MapI extends Map {
__Item[key] {
get => base.__Item[StrLower(key)]
set => base.__Item[StrLower(key)] := value
}
}
As I've probably said (in different ways) multiple times now, "pairing syntax" is only useful if you have pairs to set when you create the object. If you do, that's often because they are literally a set of
related properties (or variables), like in your myMap example, where "name" and "age" are
properties of a person.
The distinction to be made is whether you have a
limited set of known names rather than a
variable number of arbitrary keys, as I already said in different words.
Re: Map shorthand
Posted: 21 Oct 2019, 06:58
by nnnik
I just don't see why you would advise the usage of a feature that breaks under rare circumstances but supplies features that are used just as rarely over another feature of the language that works consistently.
It's like you want to make this language difficult on people.
Re: Map shorthand
Posted: 21 Oct 2019, 08:19
by guest3456
nnnik wrote: ↑21 Oct 2019, 06:58
I just don't see why you would advise the usage of a feature that breaks under rare circumstances but supplies features that are used just as rarely over another feature of the language that works consistently.
i'm confused as to what you are implying. from what i can tell, lexikos is arguing AGAINST the usage of a feature the breaks under rare circumstances (that feature being using Objects), and he is saying you should use a Map instead for these rare cases.
probably most of the time people would just be using regular objects since most normal usage would be to define properties of an object. i don't even know when or why i'd use a map. i can't think of a usage when i'm faced with an "variable number of arbitrary keynames" unless i'm trying to import a literal "
dictionary" into a script
nnnik wrote: ↑21 Oct 2019, 06:58
It's like you want to make this language difficult on people.
i don't think that's what he
wants, but that's how its trending, at least to me. but maybe i'm not as good of a programmer as you guys
Re: Map shorthand
Posted: 27 Oct 2019, 11:59
by swagfag
i made a mistake earlier, u in fact can use other objects as keys in objects, so heres the revised "should i use a Map?" flowchart:
do u need case-sensitive keys? yes: use a Map, no: go next check
do u need a key called base? yes: use a Map, no: go next check
use an object
just read
https://www.autohotkey.com/boards/viewtopic.php?p=289656#p289656
Re: Map shorthand
Posted: 29 Oct 2019, 02:41
by lexikos
swagfag wrote:i made a mistake earlier
I think you made more than one mistake.
1. Maps have keys. Objects have
property names.
2. Property names must be strings. If you use a number, it will be converted to a string. If you use an object, it is converted to an empty string, as per the v1 rule:
If an object is used in any context where an object is not expected, it is treated as an empty string.
However, that's a bug. It should throw an exception.
Re: Map shorthand
Posted: 29 Oct 2019, 07:38
by swagfag
damn it, i had only tested it with a single keys, leading me to believe the v1 behavior was retained(in reality, the objects were being converted to empty strings as u say). i shouldve stuck with my original post
well anyways, glad we could at least finally get to the bottom of this
Re: Map shorthand
Posted: 30 Oct 2019, 01:46
by nnnik
Well I will present an alternative for everyone who just likes to keep it simple:
Need to associate keys with values? Use maps.
Re: Map shorthand
Posted: 31 Oct 2019, 19:29
by buliasz
In my opinion
"key": "value" syntax is most readable one for maps (with colon in the middle), so I would use something like this:
Code: Select all
map := [
"key1" : "value1",
"key2" : "value2",
...
]
Or this:
Code: Select all
map := Map() {
"key1": "value1",
"key2": "value2",
...
}
Re: Map shorthand
Posted: 01 Nov 2019, 05:45
by lexikos
@buliasz
lexikos wrote: ↑19 Aug 2019, 03:30
One problem is that
[] creates an empty
Array and
{} creates an empty Object, so overloading based on whether there are key-value pairs vs. just values would not completely work.
The second case overlaps with function definitions. Function definition expressions, where full functions are defined and referenced within an expression, are not supported yet but are planned.
The use of
: for pairing parameters of
{} (which is just
Object() in disguise) is trivial to extend to other functions, as in
Map("key": "value") or
DllCall("IsWindow", ptr: aHwnd), but it's a bit odd to have special syntax for specific functions. It also overlaps with potential support for named parameters in general, which could potentially be utilized by DllCall in the same manner, but maybe not Map, because...
lexikos wrote: ↑19 Aug 2019, 03:30
It is unlikely that any "shorthand" syntax I add for Map will allow quote marks to be omitted. Object notation allows it because they are "properties", and the usual syntax for accessing them does not use quote marks. (Now it makes more sense to
require the quote marks to be omitted for properties.) Map, on the other hand,
always requires quote marks around literal keys.
One new idea is to have a separate function calling syntax specifically for a list of pairs, where each item is merely a parameter, but must be specified in pairs. For example,
Map{"key": "value"}.
An older idea...
myCol {Prop: 4, [1]: "first"} could be translated to
(myCol.Prop := 4, myCol[1] := "first", myCol). That is, it could be shorthand for changing multiple properties/elements, and would naturally also work for
Collection.new() {...}. However, it might be difficult to parse in cases like
getObject() {Prop: "to set"} which look like function definitions.
Source: Object.ahk/Class.md at master · Lexikos/Object.ahk
A slight change to reduce ambiguity:
myCol.{Prop: 4, [1]: "first"}. However, it would probably be clearer as
myCol.{Prop := 4, [1] := "first"}. It could be extended to
obj1.{prop, [index]} := obj2 to copy
obj2.prop and
obj2[index] to
obj1. This is all theoretical and likely to complicated for the current parser.
Some other options I've considered:
- {{ ... }}, which isn't otherwise valid (or ambiguous) because the outer {} has only one item.
- #{ ... }, which has the (misleading) connotation that it is creating a "hash" (technically, hash table, which Map is currently not).
With something like
Metalua, but for AutoHotkey, we could easily trial syntax ideas...
But I still think dedicated syntax for Map is unnecessary.
If you want to make a clear distinction between keys and values, you can always use a normal assignment.
Re: Map shorthand
Posted: 01 Nov 2019, 06:49
by Helgef
But I still think dedicated syntax for Map is unnecessary.
I agree. Especially if more maps, eg hash or case insensitive ones, are added in the future, any short hand syntax would either be very limited or perhaps not very short.
A slight change to reduce ambiguity: myCol.{Prop: 4, [1]: "first"}.
This is interesting, I like it better than the subsequent versions.
Cheers.
Re: Map shorthand
Posted: 22 Apr 2021, 19:14
by iseahound
Is there really no easy way to construct key: value pairs?
Code: Select all
MapObj.__New(Key, Value, Key2, Value2, ...)
![See-No-Evil Monkey :monkeysee:](./images/smilies/emoji_u1f648.png)