[whatwg] WebIDL vs HTML5 storage changes - delete behavior

On Sun, 18 May 2008, Maciej Stachowiak wrote:
> On May 18, 2008, at 3:18 PM, Brady Eidson wrote:
> >
> > While I'm on the topic, I'm also curious about that [XXX] placeholder. 
> > There's a bug in WebKit's bugzilla pointing out that the IE8 beta and 
> > Firefox 2 both support `delete storage.keyName` syntax as an alias for 
> > `storage.removeItem(keyName)`
> >
> > I'm taking a guess here and assuming supporting the `delete` syntax is 
> > the implied concept behind [XXX]
> 
> WebKit's JavaScript engine doesn't currently have the ability to run 
> custom code when a property is deleted. It would be a significant 
> challenge to add this capability and possibly a performance regression; 
> and no other DOM-related spec requires this, even when there is 
> NameGetter or IndexGetter behavior. For example NodeLists and 
> HTMLCollections do not let you delete by name to remove the item (I'm 
> not sure what that would even mean). So I'd prefer not to have to 
> introducethis concept just for this one case.

On Sun, 18 May 2008, Brady Eidson wrote:
> 
> WebKit has the ability to add custom property deletion on a per-class 
> basis - therefore not slowing down the common case at all.  That's how I 
> fixed the bug to make us compatible with IE8 and Firefox for now as this 
> debate gets underway...

On Mon, 19 May 2008, Geoffrey Garen wrote:
> 
> It is *very* weird, and therefore not a "useful shorthand."
> 
> In JavaScript, "delete" means "remove this property / interface from 
> this JavaScript object." I can't think of any context in which it means 
> anything else.
> 
> For example, "delete node.parentNode" attempts to remove the 
> "parentNode" property from "node". It does not remove "parentNode" from 
> the document or anything like that.
> 
> "delete window" attempts to remove the "window" property from the global 
> object. It does not close the window or anything like that.
> 
> In other words, you can be certain that "delete" is a simple operation 
> with a consistent side-effect.
> 
> As a JavaScript programmer, I would find it very difficult to reason 
> about objects that might or might not change the behavior of the 
> "delete" operator. One reason i would find it very difficult is that 
> operator overloading does not exist in JavaScript at all, so to 
> understand this one API, I would need to understand a vast corpus of 
> programming language goobery that is not at all covered in any 
> JavaScript manual. Another reason I would find it very difficult is that 
> the overloaded meaning of "delete" here ("remove persistent storage from 
> disk") is far afield from the original meaning ("remove interface from 
> temporary object in memory"). To give you an analogy, even in C++, where 
> you're allowed to overload operator delete, if you overloaded operator 
> delete to mean "do not free this object's memory, but do delete the file 
> it references from the file system", well, let's just say that your 
> patch would not pass code review with any of your four reviewers :).
> 
> I am not sure if any JS decoration or collection libraries depend on the 
> canonical behavior of operator delete, but if they do, I would hate for 
> them all to have to ship with the asterisk, "BEWARE: do NOT use this 
> decoration / collection library with that one weird DOM object that 
> interprets 'delete' to mean 'remove important data from the user's 
> disk'". Oy!

On Mon, 19 May 2008, Brady Eidson wrote:
> 
> I'm unsure if you have the proper background with the Storage interface 
> that is in question here.  I'm guessing that the reason that Firefox 2 
> and IE8 support the "modified" behavior of delete for Storage items is 
> because the "way of thinking about Storage items" we're trying to get 
> across meets most of the expectations of manipulating properties that 
> you lay out below.
> 
> On May 19, 2008, at 3:18 PM, Geoffrey Garen wrote:
> > 
> > In JavaScript, "delete" means "remove this property / interface from 
> > this JavaScript object." I can't think of any context in which it 
> > means anything else.
> 
> The spec makes it clear that storage items and properties on the Storage 
> object are interchangeable.
>
> `storage.foo = "bar"` happens to be equivalent to 
> `storage.setItem("foo", "bar")`, but is also no different from 
> `someRandomObject.foo = "bar"` as far as keeping a collection of 
> properties on an object.
> 
> This also applies for enumeration, etc.
> 
> Equivalently and more relevant to the discussion, `delete storage.foo` 
> happens to be equivalent to `storage.removeItem("foo")`, but is also 
> *little* different from `delete someRandomObject.foo`
> 
> > For example, "delete node.parentNode" attempts to remove the 
> > "parentNode" property from "node". It does not remove "parentNode" 
> > from the document or anything like that.
> >
> > "delete window" attempts to remove the "window" property from the 
> > global object. It does not close the window or anything like that.
> 
> In the SessionStorage case, this applies with zero caveats.  In the 
> LocalStorage case, it applies with the caveat that "all of the 
> properties you set on this object will still be on this object's analog 
> the next time you restart the browser and come back to this page"
> 
> And that's the really weird thing, I think - window.localStorage can be 
> thought of exactly like every other javascript object, except it is not 
> temporary.  It gets created once and maintains it's state over browser 
> launches.  We're already breaking the javascript-assumption-mold when 
> you get into that mindset.
> 
> Neither IE8 or FFX have implemented LocalStorage in a release yet, so 
> perhaps they would not support the syntax for LocalStorage, and only 
> support it for SessionStorage.  Of course that would be even weirder, 
> having 2 concrete implementations of the same interface have "API 
> incompatibilities"
> 
> > In other words, you can be certain that "delete" is a simple operation 
> > with a consistent side-effect.
> >
> > As a JavaScript programmer, I would find it very difficult to reason 
> > about objects that might or might not change the behavior of the 
> > "delete" operator.
> 
> Is the behavior of the delete operator "remove the property from the 
> object" or is it actually "remove the property from the object with zero 
> other detectable side effects"?
> 
> > One reason i would find it very difficult is that operator overloading 
> > does not exist in JavaScript at all, so to understand this one API, I 
> > would need to understand a vast corpus of programming language goobery 
> > that is not at all covered in any JavaScript manual.
> 
> I think this is a pretty shameful exaggeration ;)
> 
> > Another reason I would find it very difficult is that the overloaded 
> > meaning of "delete" here ("remove persistent storage from disk") is 
> > far afield from the original meaning ("remove interface from temporary 
> > object in memory").
> 
> The overloaded meaning of "delete" here is "remove interface from 
> temporary object in memory, as well as the persistent record of its 
> existence."  Still different from the original meaning, but not "far 
> afield" different.
> 
> > To give you an analogy, even in C++, where you're allowed to overload 
> > operator delete, if you overloaded operator delete to mean "do not 
> > free this object's memory, but do delete the file it references from 
> > the file system", well, let's just say that your patch would not pass 
> > code review with any of your four reviewers :).
> 
> But if you overloaded the delete operator to free the object's memory 
> *and* delete its referenced files from the file system, you'd be using 
> the operator overloading in its intended capacity.
> 
> > I am not sure if any JS decoration or collection libraries depend on 
> > the canonical behavior of operator delete, but if they do, I would 
> > hate for them all to have to ship with the asterisk, "BEWARE: do NOT 
> > use this decoration / collection library with that one weird DOM 
> > object that interprets 'delete' to mean 'remove important data from 
> > the user's disk'". Oy!
> 
> At the same time, why not be concerned that such a collection library 
> happens to expose the exact same API interface that the Storage object 
> exposes, and now that library should carry the same warning saying 
> "BEWARE: do NOT use this collection library with that one weird DOM 
> object that interprets 'clear()' to mean 'remove important data from the 
> user's disk'?
> 
> The fact that we're giving scripts the ability to directly manipulate 
> data on the users disk is already a jump-off-a-bridge as far as I'm 
> concerned. Shouldn't a script writer using LocalStorage use due 
> diligence to make sure his data is actually safe as expected?

On Mon, 19 May 2008, Maciej Stachowiak wrote:
>
> I think the analogy between delete in C++ and delete in JavaScript is 
> strained. First of all, the two delete operators do totally different 
> things. Second, C++ supports general operator overloading for nearly 
> every operator. The right analogy would be removing objects from 
> collections, and C++ does not have a special operator for that.
> 
> (But as a side note I think it would be poor style for C++ code to 
> overload operator delete to remove files from the filesystem. The right 
> place to do additional resource management would be the destructor.)
> 
> I do agree that the spec should define a single interoperable behavior 
> and we should all converge.

On Tue, 20 May 2008, Kristof Zelechovski wrote:
>
> Suppose you successfully delete a property of an object that gets 
> ultimately persisted that object on the server using XMLHttpRequest with 
> JSON.  Your action of deleting the property is absolutely legal and it 
> undoubtedly has side effects.  How is it different from the local 
> storage case, except that it is persisted implicitly by the session 
> manager?
>
> In other words, deleting a property from local storage does not change 
> anything in persistent memory by itself; it is the session manager that 
> executes the change afterwards.  It is possible because the local 
> storage belongs to the global state.  The operator delete is not 
> overloaded.

On Mon, 19 May 2008, Maciej Stachowiak wrote:
> 
> I looked into this and in all other cases we use an override of delete 
> for the following effects:
> 
> - Special case for Arrays since they store some of their properties 
> differently.
> - Prevent deletion (though it would be better in most of these cases to 
> just rely on DontDelete attributes)/
> - Cross-site scripting security checks on delete.
> 
> I think the Storage case would be more complicated than this, because it 
> dispatches an event and so can run arbitrary JavaScript code. I think 
> our JS interpreter is likely not prepared for "delete" executing 
> arbitrary JS code, and so may crash when this happens. We can fix it, 
> but I think delete having special behavior is not that great from the 
> point of design.
> 
> Comparing conciseness and familiarity:
> 
> storage.keyName
> storage.getItem('keyName')
> 
> storage.keyName = 'value';
> storage.setItem('keyName', 'value');
> 
> delete storage.keyName;
> storage.removeItem('keyName');
> 
> The getter seems like the biggest relative increase in conciseness, and 
> the getter and setter will both be much more familiar with operator 
> syntax. But delete is fairly rarely used (and unlike getters and setters 
> does not allow overriding at the JS level in many implementations) so 
> the syntax is not much more familiar. The improvement in conciseness is 
> also less.
> 
> We should also keep in mind that overloading operators is kind of a big 
> deal and should not be done lightly. If the HTML5 spec required custom 
> behavior for * or && for certain objects rather than following the JS 
> rules I think we would all be pretty concerned.
> 
> So I'd rather avoid messing with the (relative) purity of the delete 
> operator.

On Tue, 20 May 2008, Robert O'Callahan wrote:
>
> If "storage.keyName = 'value';" can create a new storage item 
> (persistently), won't authors expect "delete storage.keyName;" to remove 
> it (persistently), as a matter of consistency?
> 
> If overloading "delete" is too quirky or too hard to implement, then it 
> seems none of the other shorthands should be allowed either.

On Mon, 19 May 2008, Maciej Stachowiak wrote:
> 
> Many objects in the DOM implement custom name getters (for instance 
> NodeList) and a few even implement custom name setters 
> (CSSStyleDeclaration, at least the way it is done in WebKit) but no one 
> has clamored for a custom deleter or expected delete to work "as a 
> matter of consistency" or been confused that "style.opacity = 0" is 
> allowed but "delete style.opacity" is not. So I would say the available 
> evidence argues against your conclusions.

On Mon, 19 May 2008, Brady Eidson wrote:
> 
> I am a lot more swayed by this argument against adoption.
> 
> At this point, my concerns are not of a technical nature, but rather of 
> a "real life web" nature - either you force FFX and IE8 to remove it, 
> you have others adopt it, or the spec introduces a de facto 
> incompatibility on the web.
> 
> I have no solution, only this particular awareness of the problem.

Since we have implementations, and implementors don't seem willing to 
remove it, I haven't removed the 'delete' functionality for Storage.

I have, however, removed the similar functionality in UndoManager, lest 
someone implement it.



On Tue, 20 May 2008, Maciej Stachowiak wrote:
> Ian wrote:
> >
> > Originally, I wanted Storage objects to be indistinguishable from 
> > Object objects in JS, and native hash or collection objects in other 
> > bindings. Conceptually, that's what these objects are -- native 
> > name/value pair collections that happen to be mapped to non-volatile 
> > storage (or somewhat- volatile storage, in the case of 
> > sessionStorage).
> 
> Normal objects don't fire DOM events when you change their properties (I 
> imagine the same may be true of native hash objects in at least some 
> languages), so the indistinguishability only goes so far.

Well, .watch() supported by some UAs somewhat goes against this. But ok.


> > I'd also like the "delete" operator to work on DOMStringMap (for the 
> > dataset object -- calling 'delete' on that has the side-effect of 
> > removing the underlying attribute) and UndoManager (where the 
> > side-effect is to remove the entry and renumber the following entries, 
> > so maybe that's not such a good idea after all), for what it's worth. 
> > If we want to decide that we're not supporting this, we should decide 
> > that before implementations of those come about.
> 
> Those both sound suboptimal to me. UndoManager because it remove more 
> than the one item, and DOMStringMap because (a) you can't delete from 
> NamedNodeMap to remove an attribute so it would be inconsistent and (b) 
> removing an attribute causes a mutation event to fire and thus runs 
> arbitrary code (creating the same problem of 'delete' running arbitrary 
> code as Storage).
> 
> > For DOMStringMap, my intention was to not provide methods at all, and 
> > only provide the JS-native mechanisms.
> 
> A bold choice, but I would not recommend it as the sole available 
> mechanism.

See above for UndoManager, but for DOMStringMap I don't want to add any 
other mechanisms, because they introduce name clashes. Right now the IDL 
for DOMStringMap is:

   [NameCreator, NameDeleter, NameGetter, NameSetter]
   interface DOMStringMap {};

It basically emulates a JS Object. It's intended only for JS. I don't see 
why this is a bad idea.

-- 
Ian Hickson               U+1047E                )\._.,--....,'``.    fL
http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

Received on Tuesday, 13 January 2009 01:40:05 UTC