This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 25343 - Expose an isClosed property on Blob Objects
Summary: Expose an isClosed property on Blob Objects
Status: RESOLVED FIXED
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: File API (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Arun
QA Contact: public-webapps-bugzilla
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-04-14 21:19 UTC by Arun
Modified: 2014-05-16 21:29 UTC (History)
4 users (show)

See Also:


Attachments

Description Arun 2014-04-14 21:19:32 UTC
A boolean isClosed attribute should be exposed on Blobs.

It should be set to false by the Blob constructor.
The close() method sets it to true.

This should take the place of the present "0 byte" setting for size, which doesn't seem correct.
Comment 1 Glenn Maynard 2014-04-15 03:32:46 UTC
I don't think this is harmful (and it's significantly better than the 0-byte hack), but it'd be good to establish what the use case is for exposing this at all.
Comment 2 Arun 2014-04-24 18:05:44 UTC
Use Case: 

If a Blob is closed, a read will fail, and affiliated operations (such as generating Blob URLs) will fail within their prescribed error functionality (e.g. with a network error). This property will give an indication to the caller of a read operation or a URL generation operation whether or not the Blob has been closed by other script blocks.
Comment 3 Glenn Maynard 2014-04-24 19:22:32 UTC
That's not a use case.
Comment 4 Arun 2014-04-24 20:26:55 UTC
(In reply to Arun from comment #2)
> Use Case: 
> 
> If a Blob is closed, a read will fail, and affiliated operations (such as
> generating Blob URLs) will fail within their prescribed error functionality
> (e.g. with a network error). This property will give an indication to the
> caller of a read operation or a URL generation operation whether or not the
> Blob has been closed by other script blocks.

A specific example might be a WebGL program such as a game using Blobs for textures. During game play, one of the textures is invalidated (by user action; e.g. as in http://learningthreejs.com/data/live-video-in-webgl/ one of the videos would change as a result of a game play action) and the Blob is closed, to make way for new Blobs. The Blob closing (which also revokes URLs) should be tested for, so that the data isn't read again.

But I think all use cases would fall into the above category: that is, to determine whether or not to perform a Blob operation, or another culling operation.
Comment 5 Glenn Maynard 2014-04-24 20:43:00 UTC
Just throw away the blob after closing it.

this.my_blob.close();
this.my_blob = null;

It's just like how you don't need to test if a file descriptor is closed, you just don't hang onto them after you close them.

(Again, I don't think this is harmful and I don't mean to push against it, I just want to know that there's a reason to add it...)
Comment 6 Arun 2014-04-24 20:46:10 UTC
(In reply to Glenn Maynard from comment #5)
> Just throw away the blob after closing it.
> 
> this.my_blob.close();
> this.my_blob = null;


In this case, you're setting the Blob to null, and code might do a null check (or an if not null check). This certainly makes it unnecessary to have a property like isClosed, but it is still a check! isClosed explicitly checks for closed.


> 
> It's just like how you don't need to test if a file descriptor is closed,
> you just don't hang onto them after you close them.


In the example with textures, you might hang on to it *till* it's closed.


> 
> (Again, I don't think this is harmful and I don't mean to push against it, I
> just want to know that there's a reason to add it...)


I'd like other use cases, too, but I think it's useful to have.
Comment 7 Glenn Maynard 2014-04-24 20:54:29 UTC
(In reply to Arun from comment #6)
> In this case, you're setting the Blob to null, and code might do a null
> check (or an if not null check). This certainly makes it unnecessary to have
> a property like isClosed, but it is still a check! isClosed explicitly
> checks for closed.

It's not a check that requires adding something extra to Blob.

> > It's just like how you don't need to test if a file descriptor is closed,
> > you just don't hang onto them after you close them.
> 
> 
> In the example with textures, you might hang on to it *till* it's closed.

I just mean that you throw away the blob in the same place that you close them.
Comment 8 Simon Pieters 2014-05-06 07:58:34 UTC
(In reply to Arun from comment #6)
> I'd like other use cases, too, but I think it's useful to have.

This seems backwards. :-) You don't start with a solution and then try to think of cases where it would be useful. You start with a problem and then try to come up with solutions that solve the problem.

In the game scenario with textures, the use case is adequately handled by losing the reference to the blob, as Glenn pointed out.

Are there other use cases?

It's hard to evaluate whether the property makes sense without understanding how it would be used. For instance, I don't see why it shouldn't be exposed as a .readable property with inverted semantics, so that if you want to check it before reading a blob, you can use it directly in an `if` without flipping the value.
Comment 9 Glenn Maynard 2014-05-06 14:40:42 UTC
Having to type "!" doesn't matter, and "readable" suggests that it might be connected to things other than the blob being closed, such as whether a user file underlying a File is still accessible (which it wouldn't).

(Actually, you'd be adding that one ! character in my code, not removing it, since I try to write "if(blob.isClosed) return; ...", not "if(!blob.isClosed) { ... }".  Flat code is generally easier to follow than heavily nested code.)

But, yeah, this is a case of "it seems like it would make sense to have this feature, let's think up reasons to add it".  That's not always a bad thing, since you can find legitimate use cases that you might have otherwise missed, as long as it's dropped if use cases don't actually materialize.  This can always be added later if they do.
Comment 10 Arun 2014-05-07 03:17:58 UTC
(In reply to Simon Pieters from comment #8)
> (In reply to Arun from comment #6)
> > I'd like other use cases, too, but I think it's useful to have.
> 
 
> In the game scenario with textures, the use case is adequately handled by
> losing the reference to the blob, as Glenn pointed out.


Yes, a "workaround" to my example using null/losing references is possible. But losing the reference is *semantically different* than closing a Blob. Losing a reference makes slice() calls fail by definition, but closing a Blob means you can still slice() it, and even coin a Blob URL on it (but that Blob URL will return a network error).

> 
> Are there other use cases?


So, this could be the rub. As Glenn points out, this is definitely a "it seems like a good idea" situation (over IRC). Developers *should* be able to tell why certain operations fail. I feel like there are other use cases, since I feel strongly that we should allow developers to test for closed Blobs. I agree with backing this out if we do an inadequate job of proving my point, though.
Comment 11 Simon Pieters 2014-05-07 07:32:26 UTC
I don't really object to exposing it, but it hasn't been backed by a convincing use case IMHO.

It seems you added it to the spec already.

You shouldn't both say that isClosed returns true/false depending on readability state *and* set isClosed to true/false in other algorithms when setting the readability state (in slice(), close(), new File(), new Blob()). Do one or the other.
Comment 12 Arun 2014-05-07 15:48:33 UTC
(In reply to Simon Pieters from comment #11)
> I don't really object to exposing it, but it hasn't been backed by a
> convincing use case IMHO.
> 
> It seems you added it to the spec already.


I feel strongly that it should be there. I agree that the loss of reference / null argument is a good workaround to the previous use case, but that is semantically and functionally different from .close(). I'll remove it if it's demonstrably harmful or if all implementers determine it is redundant.


> 
> You shouldn't both say that isClosed returns true/false depending on
> readability state *and* set isClosed to true/false in other algorithms when
> setting the readability state (in slice(), close(), new File(), new Blob()).
> Do one or the other.


OK, done:

new Blob(): http://dev.w3.org/2006/webapi/FileAPI/#constructorBlob
slice(): http://dev.w3.org/2006/webapi/FileAPI/#slice-method-algo
close(): http://dev.w3.org/2006/webapi/FileAPI/#close-method
new File(): http://dev.w3.org/2006/webapi/FileAPI/#file-constructor
Comment 13 Glenn Maynard 2014-05-07 15:51:09 UTC
Please explain why you feel strongly that it should be there, despite the fact that you can't come up with any use cases.
Comment 14 Arun 2014-05-07 17:49:03 UTC
(In reply to Glenn Maynard from comment #13)
> Please explain why you feel strongly that it should be there, despite the
> fact that you can't come up with any use cases.

First, it's not true that there aren't any use cases. You've merely provided a (reasonable) workaround; it doesn't necessarily invalidate the use case. It is still a use case that could make use of both close() and a test for closure.

Any question about a property like .isClosed can equally be asked about close() -- why have a close() at all, if explicit reference nulling can be availed of? The intent was to allow web developers a chance to manage their applications' use of memory by marking Blobs disabled for memory intensive operations (e.g. read). But couldn't they just as easily set to null or work with loss of reference explicitly? This might cause network errors as well, and return failure on reads, which are desired in this case. A good history of close() is in Bug 16952; in particular, from Bug 16952 Comment 17, is this:

"The thing is that a Blob can generally be passed around through a lot of parts of a code-base due to it's mostly-readonly nature.

This could mean that just because part of the code closes a Blob, doesn't always mean that another part of the code which has a reference to the same Blob, is always aware."

While we can rely on operation failure, I think the web developer should be able to test before calling an operation. And, note that some operations don't fail, like slice() -- it merely coins a closed Blob. 

If we introduce a capability with this kind of semantics, we should allow a web developer to test for it, no, and not merely keep it internal? A different part of the code may need to be made aware of the closure from the explicit calling code.

Forcing a full reference loss is radical and stops all operations. Here, we only stop reading; it's been suggested that a different bug might be filed to allow the structured clone algorithm to proceed unimpeded. So since we have a mix of operations that might continue as well as that might fail (because of the distaste for throwing), then we should have a property that allows a web developer a chance to check. That's why I feel strongly.
Comment 15 Glenn Maynard 2014-05-07 21:42:15 UTC
(In reply to Arun from comment #14)
> First, it's not true that there aren't any use cases. You've merely provided
> a (reasonable) workaround; it doesn't necessarily invalidate the use case.
> It is still a use case that could make use of both close() and a test for
> closure.

It's not a workaround, it's a straightforward coding pattern.  Something isn't a use case needing a solution if there's already a perfectly reasonable way to do it.

> Any question about a property like .isClosed can equally be asked about
> close() -- why have a close() at all, if explicit reference nulling can be
> availed of? The intent was to allow web developers a chance to manage their
> applications' use of memory by marking Blobs disabled for memory intensive
> operations (e.g. read). But couldn't they just as easily set to null or work
> with loss of reference explicitly? 

No, because if you set it to null, the data can't be freed until the object is garbage collected.  The whole premise of close() is to allow memory and/or disk space to be reclaimed without having to wait for GC.

> If we introduce a capability with this kind of semantics, we should allow a
> web developer to test for it, no, and not merely keep it internal? A
> different part of the code may need to be made aware of the closure from the
> explicit calling code.

If you throw away the blob when you close it, there's no case where any other code needs to know if the blob is closed, since you'll never give them one that is.

It's not even clear to me why you'd want to check that.  Even if you're handed a closed blob, you can just do whatever you were going to do, and if it's closed it'll fail normally when you try to read it.  You already have the error handling paths for that (since the read might fail for other reasons), and adding an error check for something that you're already handling is just adding new bug vectors and code paths to test.  It sounds like a premature optimization...
Comment 16 Jonas Sicking (Not reading bugmail) 2014-05-08 20:53:37 UTC
I don't have a strong opinion here.

However I'll note that keeping internal hidden state in APIs generally always result in that we get asked to expose that state because it's easier in some web developer's architecture.

I.e. while it's easy for us to say that you could always do

someObj.the_blob.close();
someObj.the_blob = null;

things might not be as simple in all web apps. I.e. maybe there might be a whole host of "someObj" objects that all point to the same blob. Tracking all of them down might add considerable complexity.

This was the same reason that we added IDBObjectStore.name. In theory it's always quite easy to track the name of an object store, since the only way you can get a reference to it in the first place is by knowing its name and calling transaction.objectStore(name). And the implementation will basically have to track the name internally in the object anyway in order to implement it's functionality, like IDBObjectStore.get().

So since the spec basically requires that the name is kept in the object, and the name does significantly affect the object's behavior, exposing it seemed like a very low cost and of potential value to authors.


I think the same thing applies here. Any reasonable implementation of Blob is going to track internally if .close() has been called or not. Exposing it is bound to have very low implementation cost. I hate the idea that not exposing it would cause developers to do *any* extra work in order to work around the shortcoming. I'd much rather that they spend the time developing awesome features for users.

Developers might definitely be able to work around not having .isClosed available. But what's the value of asking them to given the extremely low implementation cost?


Similarly, I don't see that the implementation cost of this feature could go up in the future. I.e. I don't see any risk that this would prevent us from making any changes to the API in the future, or that it would prevent any implementation strategy for developers.

If there was any concern that adding .isClosed would have a higher cost in the future then I'd definitely agree that we should wait for stronger use cases before adding it.

Is there any such concern here?
Comment 17 Simon Pieters 2014-05-12 12:30:02 UTC
That seems reasonable.

OTOH, maybe developers will get into a habit of always checking .isClosed before reading even if there's no reason for doing so, which is wasting time. Or they think it is enough to check "isClosed" and think it is a guarantee that it will be readable, and don't handle the other error cases.
Comment 18 Arun 2014-05-12 15:15:00 UTC
(In reply to Simon Pieters from comment #17)
> That seems reasonable.
> 
> OTOH, maybe developers will get into a habit of always checking .isClosed
> before reading even if there's no reason for doing so, which is wasting
> time. Or they think it is enough to check "isClosed" and think it is a
> guarantee that it will be readable, and don't handle the other error cases.


I can't argue with this. It's quite possibly true that this feature can lead to shallow error handling. However, the same argument was made about Blob.close() itself, and this property is tightly coupled to some code block within the web developer's purview actually *calling* Blob.close(); other error conditions might occur outside of the purview of a web developer's code (e.g. file errors).

On balance, I'm still closer to wanting to put it in than leaving it out. Everyone one else that has commented here seems closer to the middle ground (e.g. no strong opinions).

This point from Comment #16 seems to help decide matters:

"If there was any concern that adding .isClosed would have a higher cost in the future then I'd definitely agree that we should wait for stronger use cases before adding it.

Is there any such concern here?"

I'm not sure what exactly would constitute higher cost.
Comment 19 Simon Pieters 2014-05-13 06:51:09 UTC
I'm not aware of any particular impl costs with exposing it.

I think this feature has been given enough consideration at this point, and on balance I agree it's OK to have it in. So let's close this as FIXED.
Comment 20 Glenn Maynard 2014-05-16 21:29:12 UTC
(In reply to Jonas Sicking from comment #16)
> I.e. while it's easy for us to say that you could always do
> 
> someObj.the_blob.close();
> someObj.the_blob = null;
> 
> things might not be as simple in all web apps. I.e. maybe there might be a
> whole host of "someObj" objects that all point to the same blob. Tracking
> all of them down might add considerable complexity.

Closing blobs isn't a mechanism to shut actions down on a blob, because it doesn't propagate to slices or structured clones--you may have a whole host of *slices* of the blob--and it doesn't affect ongoing async operations (closing a resource immediately after starting a read, before the read finishes, looks like a basic pattern).  close() is just a mechanism to allow storage to be freed deterministically, not a way to signal your own code to stop doing something.

There are no use cases for this, so it's just interface bloat, and may encourage people to misinterpret the point of closing blobs.