Issues about private-in
July 23, 2020 · View on GitHub
Note: English translation is incomplete.
主旨 TL;DR
我们很不满意public/private fields的语法语义失配的情况(语法非常接近但背后语义截然不同),即使无法修复,我们也不希望其他提案继续扩大这种失配。
We are unhappy with public/private fields syntax/semantic mismatch, even we can't fix it, we don't want to see the mismatch increasing further.
因此我们反对private-in提案以当前形式进入stage 3,除非明确其语法变动风险,允许根据潜在的reification的最终状态进行对应的修改。
So we block private-in proposal, unless mark its syntax has risk and would be changed in stage 3 according to the final status of potential reification proposal.
分析 Analysis
既有之物 What already in JS
ES3
// static
obj.foo
// dynamic
const key = 'foo'
obj[key]
key in obj
ES5
// reflection
Object.getOwnPropertyDescriptor(obj, key)
ES6
// symbol added
const key = Symbol()
// no static syntax
// dynamic: nothing changed
obj[key]
key in obj
// reflection
Object.getOwnPropertyDescriptor(obj, key)
// Proxy added
new Proxy(obj, handler)
// which can trap all semantics above
属性语法.、[]和in在ES3时代就确立了,具有悠长的历史。之后所添加的reflection、symbol和proxy等完善了语法到语义层面的对应。
The syntax of ., [] and in have a long history, and reflection, symbol and proxy complete the correspondence property semantics.
class fields
// static
obj.#foo
// dynamic: NA
// reflection: NA
// proxy: NA
技术上说,class fields是overload了.语法符号,建立了public和private在语法上的二元对应(所谓「#是新的_」这一口号,即this._x对应到this.#x,就是建立在这种二元性之上),但实际上public/private具有截然不同的语义(甚至public fields和public methods/accessors之间都具有微妙但致命的语义差别,即语义本身也存在严重失配,尽管这一点和本讨论无关),this.#x是基于静态作用域的,所以我们只能overload.但是不能overload动态的[]和in,且其不是属性,所以也不适用reflection和proxy。
Technically, we overloaded . syntax, which make public/private duality, but actually public/private have totoally different semantic (and even public fields have subtle but significant semantic differnce with public methods/accessors, but not relevant here.) this.#x is statically scoped, so we can only overload . but not in and [], and no refection/proxy because it's not property.
这很不好,以皮相上的相似掩盖本质上的不同,打破了自ES3时代以来这20年间所建立的持续稳定的心智模型。但面对这种坑爹情况,逆来顺受的程序员一定要安慰自己,往好处看的话,那至少有一条明确的界线,static对非static。这个明确的界线缓解了认知模型失配的痛苦。尤其如果程序员并不怎么用dynamic、reflection和proxy时(比如许多TS用户就是如此),那他们在大多数情况下不用面对这背后深藏的幽灵。(当然他们直接依赖和间接依赖的框架和库如果用了,那他们可能会被坑得更惨,但至少能多多少少地把锅甩出去。)
It's not good, surface similarity cover the essential difference, break the stable mental model of these syntax/semantics which have been built in last 20 years. But at least there is a clear line between two worlds: static vs non-static. This could mitigate the pain of mental model mismatch, if the programmers rarely use dynamic and reflection (like many TS users do) , they are even not have to know the differences in most cases.
Ergonomic brand checks for private fields (private-in)
以pubic/private二元性来说,本提案以#x in obj作为brand check的语法似乎看似ok,然而从对应性来说,显然#x in obj对应的是obj[#x]而非obj.#x。尽管我们可以争辩说反正obj[#x]是不合法的语法,最终程序员总是会重新学会我们所定义的「正确语法」。但我们认为这种语法上的随意性进一步扩大了失配的范畴(语法语义失配、语义本身失配、现在语法也失配,三毒俱全),而且模糊了前面所说的static/non-static界限,本着「勿以善小而不为,勿以恶小而为之」之原则,我们认为应寻求其他替代语法。
As the duality of public/private, using #x in obj for brand check seems ok at first glance, but obviously, as #x in obj, it should map to obj[#x] not obj.#x. Though we can argue that obj[#x] is syntax error so it would force the programmers learn what is the "correct" thing, but we feel such arbitrary rule just increase the mismatch again, make the static/non-static line vague, so we believe it's better to look after some alternatives.
Reification (private symbols)
然若#x变为某种first-class的值(所谓reification,实体化),我们就可以(也应该)overload.、in和[]这所有相关语法。于是#x in obj对应到obj[#x],而obj[#x]和obj.#x实为同义(尽管看上去为奇怪的重复,但此为const key = #x; obj[key]之副产品),则#x in obj就至少是合理的。
But if #x become first-class value, we could (and would) overload all ., in and [] syntax. So there would be #x in obj and obj[#x], which is same as obj.#x (though it seems strange, but it's a side effect of const k = #x; obj[k]), then #x in obj is reasonable choice.
尽管我们完全欣赏不来这种将不同语义overload到相同语法的设计,但至少在形式上是有一致性的。所有的表层语法都被overload,同时适用属性和private symbol,然后属性和private symbol各自遵循其语义。这样,至少没有扩大失配。
Though we don't like such overloading different semantics to same syntax, at least it have the consistency: all . related syntax are overloaded and they all applied to both properties or private symbols, and follow their semantics. So it won't increase the mismatch.
提案之间的关联 The connections between proposals
然而该提案前景不明(仍然是stage 0?),所以我们对于其最终的语义和语法毫无信心。尽管语义方面来说,brand check和reification之间可能并无影响,但语法上肯定必须是有一致性的。
But reification proposal is unclear now (still stage 0?), so we don't have the confidence of the final semantic and the corresponding syntax. Even their semantics may not affect private-in proposal, the syntax should keep same.
也就是说,万一reification使用了语法&#x(此语法来自进入stage 1时的会议纪要中的讨论内容),那么private-in也应该改用&#x in obj。因为同时具有两种语法&#x in obj和#x in obj去做同一件事情是非常令人困惑的。
That said, if reification use syntax &#x (from the meeting notes of previous meetings), private-in should also become to &#x in obj. Because it will very confusing if we have two syntax &#x in obj and #x in obj for same thing.
所以如果private-in到达stage 3,且如stage 3所意味的,语法稳定不变,则意味着private-in提案暗中限定了reification的语法。如果说一个提案进入stage 3带来对另一个提案的隐含约束还算正常;一个更重要的点在于,这是以reification提案也能最终进入JS为前提的。
So if private-in was stage 3, and as stage 3, the syntax should not be changed, it just put a implicit constraint that reification syntax also should be #x not &#x or some other forms. I hope the champion could make such effect clear in stage advance document. More important, there is another possibility, we may never have reification.
实际上很可能我们永远不会有reification,在这种情况下,private-in单独overload了in,而且是以语法失配的形式overload,那就好似过马路过到一半停下来一样。
So in that case, private-in just overload in in a mismatch form, it just like go across the road and stop in the middle of it.
总结 Summary
我们的立场是,逻辑上说,reification提案对private-in提案(也许还有private declaration提案)形成了语法设计上的关联,所以我们认为在reification提案明朗化之前,private-in不应进入stage 3。
Our postion is, logically, refication proposal and private-in proposal (maybe private declaration proposal also) have the connection of syntax design, this is why we don't want private-in go forward to stage 3 before the status of reification proposal is settled.
除非,委员会能建立共识,private-in的语法可以在进入stage 3之后根据情况进行改变:
- 如果最终存在reification,两者语法最终必须一致,且private-in不能存在两种形式;
- 如果最终不存在reification,private-in的语法不overload
in,而是改为其他某种形式。
那么我们会撤回对此提案的block。
But we will not block this proposal if champion could mark the syntax of private-in would be changed accoding to the status:
- if there is reification eventually, the syntax will be aligned and no two form for same thing;
- if there is no reification eventually, the syntax will not overload
inbut change to other form.
以上。
Thank you.
Old post
Issues about private-in
- It's not clear what
#xin#x in objmean, if it will be a first-class value (private symbol?), then we need such proposal also advance to a stage 2 (currently stage 0?) to have the confidence of the semantic and the corresponding syntax. Note we already have#xin#x = initialValueso I'm worry about the potential confusion. - Overloading of
inmight also bring the confusion. Especially as the currentinusage, people like to expectif (#x in obj) return obj[#x]or evenfor (#x in obj).#x in objandobj.#xseems mismatch. Alternative syntax (#x.has(obj)) may help, but again, we need first figure out what#xis and how the concept model we want to give to programmers, and then we can check whether the syntax matches the concept model and not increase the confusion. - Generally speaking, we are unhappy with public/private fields syntax/semantic mismatch, we don't want to see the mismatch increasing further.