qt4cg / qtspecs

QT4 specifications
https://qt4cg.org/
Other
28 stars 15 forks source link

Terse syntax for map entries #147

Closed line-o closed 1 year ago

line-o commented 2 years ago

Allow variables to be used to construct map entries with

The syntax would change to something along

mapExpression ::= 'map' '{' ( expr ':' expr | variableReference ) [ ',' ( expr ':' expr | variableReference ) ]* '}'

Example:

let $my-var := <root />
let $other := map { "a": [ 1, 2, 3 ] }
return map {
  $my-var,
  $other
}

evaluates to

map {
  "my-var": <root />
  "other": map { "a": [ 1, 2, 3 ] }
}

This is the inverse operation of destructuring a map as proposed in https://github.com/qt4cg/qtspecs/issues/37

let ${my-var, other} := map {
  "my-var": <root />
  "other": map { "a": [ 1, 2, 3 ] }
}

In the Slack discussion John Lumley and Liam Quinn raised concerns this construct might be error prone when both methods to construct an entry can be mixed

  map { $a : $b, $c }
map:for-each($m, function ($k, $v as xs:anyAtomic) { map{ $v : $k } }),
map:for-each($m, function ($k, $v as xs:anyAtomic) { map{ $v, $k } })
benibela commented 2 years ago

JSONiq had a map merge syntax that could be used similarly:


let $my-var := (:map:) { "my-var": <root/> }
let $other :=  (:map:) { "a": [ 1, 2, 3 ] }
return {|
  $my-var,
  $other
|}
line-o commented 2 years ago

Interesting, @benibela. Thanks for bringing it to attention.

Having an explicit map constructor for maps constructed by variable references was also proposed by Liam Quinn on Slack: vmap{ $a, $b }

It limits the construction of maps to exclusively use one or the other method. I do find it useful to mix both methods (as you can in JavaScript)

let {a, c} = {a:1, b:2, c:3}
let next = {a, c, q: "sth"}
line-o commented 2 years ago

The difference is of course that there is no way to construct keys from variables in object literals in JavaScript as one can in XQuery.

michaelhkay commented 2 years ago

This proposal violates the principle that variables should be substitutable by their values. This principle is very important in allowing optimization. The expression

let $my-var := <root />
let $other := map { "a": [ 1, 2, 3 ] }
return map {
  $my-var,
  $other
}

should be statically rewritable as:

map{<root />, map { "a": [ 1, 2, 3 ] }}

The danger is that optimizations are prevented even if the new feature is never used.

ChristianGruen commented 2 years ago

The danger is that optimizations are prevented even if the new feature is never used.

I had similar thoughts. Maybe the problem can be circumvented by generating the key/value representation at parse time?

michaelhkay commented 2 years ago

I would be more sympathetic if the $my-var didn't look like an ordinary variable reference, for example if it used some custom syntax like $$my-var - though I don't like that syntax.

michaelhkay commented 2 years ago

Perhaps

let $my-var := <root />
let $other := map { "a": [ 1, 2, 3 ] }
return variable-map {
  $my-var,
  $other
}
ChristianGruen commented 2 years ago

I think I agree, even though the JavaScript syntax is sometimes convenient.

Treating code and data equally can be dangerous, if not critical, for example when you perform refactorings and rename variables.

line-o commented 2 years ago

I see both map destructuring and construction of entries by variable reference as syntactic sugar. So adding a step in compilation to get to a normal form sounds about right. @michaelhkay doesn't #37 then also violate the (static) variable substitution principle?

line-o commented 2 years ago

OK, so there is some consensus in introducing a new keyword vmap, variable-map, varmap or similar. Mixing both the current and the terser syntax would then come down to

let $b := 2
return
  map:merge((
     map { "a": 1 },
     (: the new construct :)
     varmap { $b }
  ))

If it is crucial to syntactically differentiate between the two entry construction methods we could also revisit the jsoniq syntax {| $var |}.

map {| $a, $b, $c |}

I was not aware of the principle in XQuery that variables need to be able to be substituted by their value at all time.

@ChristianGruen renaming a variable is then also renaming the key. This needs then taken into account.

I also have not thought about the new record type and how it might affect this proposal.

michaelhkay commented 2 years ago

I was not aware of the principle in XQuery that variables need to be able to be substituted by their value at all time.

It's not specifically a principle for XQuery, it's a general principle of orthogonal language design in expression-based languages, that anywhere you can write the value 42, you can replace it with an expression that evaluates to 42 without changing the meaning; conversely, anywhere you write an expression, you can replace it by the value of the expression (assuming the value is effable).

line-o commented 2 years ago

If you would introduce a kind of dereferencing syntax then it might be intuitive to have it resemble the destructuring syntax for maps.

let ${a, b} := map { "a": 1, "b": 2 }
return map { ${a}, ${b}, "c": 3 }

or let $m := map { ${ a, b } } or even let $m := ${ a, b}

NOTE: There might be a better syntax for both operations, but they should be aligned.

ndw commented 1 year ago

The CG agreed to close this issue at meeting 024

line-o commented 1 year ago

@ndw Reading through the Meeting minutes this issue was closed because it is not a concrete proposal. What would be needed for this to be concrete? I want to know for future and still open proposals what the shortcomings are.

michaelhkay commented 1 year ago

That's not a good summary of why it was closed. Basically, we've been closing a few issues where the discussion explored a variety of alternatives but failed to converge on a consensus design. In such cases we've usually found that it's best to learn from the discussion, think again about what we're trying to achieve, and either drop the idea, or come up with a new proposal that meets the objections and difficulties that were encountered, and articulates the alternative options and their pros and cons.

Arithmeticus commented 1 year ago

The root idea lives on in the following threads:

334 #341 and especially #350

line-o commented 1 year ago

@Arithmeticus I read all three linked issues. To me they are unrelated as none of them addresses the construction of maps.