Version 5, changed by brian 10/10/2006. Show version history
[1:01 PM] aszs: hi brian
[1:01 PM] brian_skinner: hi aszs
[1:01 PM] aszs: i have a (relatively) radical idea
[1:01 PM] brian_skinner: hi dmachi, tk, rcoup
[1:01 PM] brian_skinner: aszs: shoot
[1:02 PM] aszs: eliminate dojo.Result
[1:02 PM] brian_skinner: that's radical!
[1:02 PM] aszs: it fixes problems and makes things simpler
[1:02 PM] aszs: instead add
[1:02 PM] aszs: oncompleted, onnext, array, onerror keywords
[1:02 PM] aszs: to find()
[1:02 PM] aszs: var results=[];
[1:02 PM] aszs: var success = find("query", { array : results });
[1:03 PM] aszs: for simply synchronous query
[1:03 PM] brian_skinner: {array: results} is optional?
[1:03 PM] aszs: yes
[1:03 PM] aszs: instead use onnext
[1:03 PM] aszs: if u don't want all the results saved
[1:03 PM] brian_skinner: give me a second to look at the current apis and think about that
[1:03 PM] aszs: { onnext : myhandlerfunc }
[1:04 PM] aszs: i thought of this because of another problem with Result
[1:04 PM] aszs: what happens if the query is synchronous and there's an error
[1:04 PM] brian_skinner: yup, that's a problem
[1:05 PM] aszs: you don't set the onerror handler till after u get a result
[1:07 PM] brian_skinner: for the synchronous error case, couldn't you just call find() and get a result object back, where the result object knows that there was an error, and when you do result.setOnError(foo) then foo will get called?
[1:07 PM] aszs: yes
[1:07 PM] dmachi: hi everybody
[1:08 PM] aszs: but then you need to have a error handler just to find if there was one
[1:08 PM] brian_skinner: hi dmachi
[1:08 PM] brian_skinner: aszs: yup, it's a little clumsy
[1:08 PM] aszs: its not a big deal
[1:08 PM] aszs: its just how i came to this new idea
[1:08 PM] dmachi: aszs: you could do something like deferred does in that if you add a callback after the results have alreayd been recieved it just callsback with those immediately (same in case of errback)
[1:08 PM] aszs: dmachi: yes
[1:08 PM] dmachi: (maybe?)
[1:09 PM] brian_skinner: dmachi, aszs: i got mail from chris -- he says he's not going to be able to make it today
[1:09 PM] dmachi: i wasn't really here either, this is just and idle channel and i got a little pop from my name being mentioned :)
[1:09 PM] brian_skinner: :)
[1:10 PM] brian_skinner: aszs: how would getLength() work?
[1:10 PM] aszs: yes
[1:10 PM] aszs: maybe result could be the length or -1 on error
[1:11 PM] brian_skinner: you mean...
[1:11 PM] aszs: if its async the length could be an arg for oncompleted
[1:11 PM] brian_skinner: var length = find(query, ...)
[1:11 PM] brian_skinner: right
[1:11 PM] aszs: yes
[1:11 PM] aszs: and if array is passed
[1:11 PM] aszs: just look at the array length
[1:11 PM] brian_skinner: right
[1:12 PM] aszs: then there's cancel
[1:12 PM] aszs: it could work like io.bind
[1:13 PM] aszs: pass abort kword
[1:13 PM] aszs: that gets set to an abort function
[1:13 PM] aszs: so abort and sync would be the same as io bind
[1:14 PM] aszs: so would error and completed
[1:14 PM] brian_skinner: i've never actually used dojo.io.bind -- i'll have to go look at it to understand about abort, error, completed
[1:15 PM] brian_skinner: so, just thinking out loud,
[1:15 PM] aszs: there just callback funcs
[1:15 PM] brian_skinner: for the sync case...
[1:15 PM] brian_skinner: var store = new dojo.data.csv.CsvStore({url:"movies.csv");
[1:15 PM] brian_skinner: var results = new Array();
[1:15 PM] brian_skinner: store.find(null, {array:results});
[1:15 PM] brian_skinner: it would be nicer to do this...
[1:15 PM] brian_skinner: var store = new dojo.data.csv.CsvStore({url:"movies.csv");
[1:15 PM] aszs: yes
[1:15 PM] brian_skinner: var results = store.find();
[1:16 PM] aszs: yes that'd be nicer but we can't do that
[1:16 PM] brian_skinner: if no oncompleted, onnext, array, onerror keywords are passed, then assume we just want a simple array
[1:16 PM] brian_skinner: and return an array
[1:16 PM] aszs: good idea
[1:16 PM] aszs: if array is null assum an error
[1:16 PM] brian_skinner: right
[1:17 PM] brian_skinner: or maybe it throws an exception if there's an error, i don't know
[1:17 PM] aszs: well this makes things *much* simpler
[1:17 PM] brian_skinner: so, what does some simple async code look like?
[1:17 PM] brian_skinner: var store = new dojo.data.csv.CsvStore({url:"movies.csv");
[1:18 PM] aszs: find("query", { onnext=myforeachfunc } )
[1:18 PM] brian_skinner: store.find(someQuery, {oncompleted: foo, onnext: bar, onerror: iggy});
[1:18 PM] aszs: well in the simple case use just need onnext
[1:19 PM] brian_skinner: yes, right
[1:19 PM] aszs: and sync=false
[1:19 PM] brian_skinner: right
[1:19 PM] aszs: or array=result and oncompleted=foo
[1:19 PM] brian_skinner: store.find(someQuery, {sync: false, oncompleted: foo, onnext: bar, onerror: iggy});
[1:20 PM] aszs: or store.find(someQuery, {sync: false, oncompleted: foo, array: result);
[1:20 PM] brian_skinner: right
[1:21 PM] brian_skinner: just off the top of your head, is it easy for you to show me an example of what abort/cancel would look like?
[1:21 PM] aszs: let me look at my RemoteStore
[1:22 PM] aszs: i use bind's abort
[1:22 PM] aszs: to implement cancel
[1:22 PM] aszs: actually i'm wrong about io.bind
[1:24 PM] aszs: they implement it this way:
[1:24 PM] aszs: kwargs = {}
[1:24 PM] aszs: io.bind( kwargs); //funct sets kwargs.abort here
[1:24 PM] aszs: var abortfunc = kwargs.abort
[1:24 PM] aszs: but the use sees this:
[1:24 PM] aszs: var request = dojo.io.bind( { ... });
[1:24 PM] aszs: result._abortFunc = request.abort;
[1:24 PM] aszs: the user i mean
[1:26 PM] aszs: i guess we could return minimal request object if its async
[1:26 PM] aszs: or do it the former way
[1:26 PM] brian_skinner: i'm confused -- so dojo.io.bind returns a request object, and that request object has an "abort" property which points to a function?
[1:26 PM] aszs: yes
[1:27 PM] brian_skinner: and you can call that function if you want to cancel the request?
[1:27 PM] aszs: yes
[1:27 PM] brian_skinner: okay
[1:27 PM] aszs: result.abort()
[1:28 PM] brian_skinner: or we could just return a *token* representing the request...
[1:28 PM] brian_skinner: var token = store.find(someQuery, {sync: false, oncompleted: foo, onnext: bar, onerror: iggy});
[1:28 PM] brian_skinner: and then...
[1:28 PM] brian_skinner: store.abort(token);
[1:28 PM] aszs: yes
[1:29 PM] aszs: but why?
[1:29 PM] brian_skinner: which isn't as object-oriented, but it means we don't even have to start any kind of conversation about what a request object is
[1:29 PM] brian_skinner: and we don't have to have a whole new file for dojo.data.Request API
[1:30 PM] aszs: io.bind doesn't define what the result object is
[1:30 PM] aszs: just has one
[1:30 PM] brian_skinner: and it defines a little bit about how it behaves
[1:30 PM] brian_skinner: it conforms to some API
[1:30 PM] aszs: but there no dojo.io.Result
[1:30 PM] aszs: just uses duck typing
[1:30 PM] brian_skinner: right -- the API only appears in documentation
[1:31 PM] brian_skinner: http://manual.dojotoolkit.org/io.html
[1:32 PM] brian_skinner: ...
[1:32 PM] aszs: the doc says there *is* dojo.io.request
[1:32 PM] aszs: i didn't see that
[1:32 PM] brian_skinner: http://dojotoolkit.org/api/#dojo.io.Request
[1:33 PM] aszs: its not in the source code
[1:33 PM] aszs: not a real object
[1:33 PM] aszs: just a dictionary
[1:33 PM] brian_skinner: it must be in the source code somewhere, or it wouldn't appear in the automatically generated API docs
[1:33 PM] aszs: hmmm
[1:34 PM] brian_skinner: well, we can look into that more later
[1:34 PM] aszs: its in common.js
[1:34 PM] brian_skinner: in any case, we can do something like that for abort/cancel
[1:34 PM] aszs: doesn't look like BrowerIO uses that...
[1:34 PM] aszs: yes, in any case...
[1:35 PM] aszs: well, what do u think?
[1:35 PM] brian_skinner: okay, getting rid of the dojo.data.Result certainly has some appeal
[1:36 PM] brian_skinner: and I like the simple API for getting an array
[1:36 PM] brian_skinner: make simple things simple
[1:36 PM] brian_skinner: but I don't have a strong sense one way or the other about which API is better -- with dojo.data.Result or without
[1:37 PM] brian_skinner: it'd be great to get feedback from a few more people about the idea
[1:37 PM] brian_skinner: see what Chris and Tom think
[1:37 PM] aszs: ok
[1:37 PM] brian_skinner: i'm happy to follow whatever the consensus opinion is
[1:37 PM] brian_skinner: we could add it to our next agenda
[1:38 PM] brian_skinner: or you could write up some mail and send it to dojo-dev, if you feel like it
[1:38 PM] aszs: i could send an email or add a wiki page
[1:38 PM] aszs: which do u think is better?
[1:38 PM] brian_skinner: yup, or a wiki page
[1:38 PM] brian_skinner: my sense is that people read mail more than they read the wiki
[1:38 PM] aszs: ok
[1:39 PM] aszs: so what would be the arguments for keeping Result?
[1:39 PM] brian_skinner: inertia ;-)
[1:39 PM] brian_skinner: i don't know -- i don't think I have any good arguments
[1:40 PM] aszs: ok
[1:40 PM] aszs: to clarify: so if find is sync return an array unless onnext is specified?
[1:41 PM] aszs: or return an array always if sync?
[1:41 PM] brian_skinner: although, maybe we actually are talking about keeping it, in some minimal sense -- you do still get back a result object, and you can call result.abort(), and maybe you can get state info, like result.inProgress()
[1:41 PM] brian_skinner: find should default to sync
[1:41 PM] brian_skinner: so that makes the rule be something like this
[1:41 PM] aszs: yes
[1:42 PM] brian_skinner: return an array unless onnext and/or sync:false have been specified
[1:42 PM] brian_skinner: i'm not sure whether it's "and" or "or"
[1:43 PM] brian_skinner: i guess "or"
[1:43 PM] brian_skinner: although it would be weird to specify sync:false and not provide an onnext:foo
[1:43 PM] aszs: if sync false
[1:43 PM] aszs: we can't return an array
[1:43 PM] brian_skinner: right
[1:44 PM] aszs: unless we return an empty array
[1:44 PM] brian_skinner: and there probably isn't much value in doing that
[1:44 PM] aszs: so i guess its "or"
[1:44 PM] brian_skinner: okay
[1:45 PM] aszs: so we don't really need an array kwarg
[1:46 PM] brian_skinner: maybe not
[1:46 PM] brian_skinner: it'd be great to not need that
[1:46 PM] aszs: onnext : function(item) { result.push(item) }
[1:46 PM] aszs: if we don't want the user to have to write that
[1:46 PM] aszs: we could say if onnext's value is not an function
[1:47 PM] aszs: will call object.push(item) on it
[1:47 PM] aszs: instead of invoking it
[1:47 PM] aszs: then you could just go onnext : myArray
[1:47 PM] aszs: sync : false
[1:47 PM] aszs: xhr does something like
[1:47 PM] aszs: i think
[1:47 PM] brian_skinner: hmmm... but that's kind of weird for large result sets
[1:48 PM] aszs: yes,
[1:48 PM] aszs: so user shouldn't do that
[1:48 PM] brian_skinner: if you know you're looking at 10,000 things -- conceptially you really don't want to "push" them onto an object
[1:48 PM] aszs: ok
[1:49 PM] aszs: we could just say onnext can be either a function or an array
[1:49 PM] brian_skinner: yes, that has some appeal
[1:49 PM] brian_skinner: but
[1:49 PM] aszs: is that better?
[1:49 PM] brian_skinner: seems like if you really want an array, then you're not going to want to see the array until after the whole loop has finished anyway
[1:49 PM] aszs: yes?
[1:50 PM] brian_skinner: so what you really want is something like this...
[1:50 PM] aszs: find( { sync: false, onnext : myarray, oncompleted: myfunc })
[1:50 PM] brian_skinner: maybe
[1:50 PM] brian_skinner: but that code would really look like this...
[1:51 PM] brian_skinner: var array = new Array();
[1:51 PM] brian_skinner: store.find( { sync: false, onnext : myarray, oncompleted: myfunc });
[1:51 PM] brian_skinner: ...
[1:51 PM] aszs: yes
[1:51 PM] brian_skinner: why should I have to create the array object?
[1:51 PM] brian_skinner: would it be better to do this...
[1:52 PM] brian_skinner: store.find( { sync:false, oncompleted: myfunc, array: true});
[1:52 PM] brian_skinner: or ...
[1:52 PM] aszs: yes
[1:52 PM] aszs: yr right
[1:53 PM] brian_skinner: store.find( { sync:false, onarrayloaded:myfunc});
[1:53 PM] aszs: and array is always true when sync = true
[1:53 PM] brian_skinner: yes
[1:53 PM] aszs: don't think we need a separate onarrayloaded
[1:53 PM] aszs: oncompleted(length, array)
[1:53 PM] aszs: array might be undefined if array : false
[1:54 PM] brian_skinner: yes
[1:54 PM] aszs: all this seems more elegant
[1:54 PM] aszs: and easier to implement stores
[1:55 PM] aszs: especially simple ones
[1:55 PM] brian_skinner: i was just thinking {onarrayloaded:myfunc} might be less confusing than {oncompleted: myfunc, array: true}, where there's some "invisible" interaction between the two parameters, myfunc and array:true, such that the params sent to myfunc are actually different depending on what array: was set to
[1:56 PM] brian_skinner: but, this is a pretty minor detail anyway
[1:56 PM] brian_skinner: ...
[1:56 PM] brian_skinner: so, should we talk about what "reference faulting", and what type of item/identity/reference you might get when you call store.get(theHobbit, "author")?
[1:56 PM] aszs: ok
[1:57 PM] brian_skinner: give me one minute...
[1:57 PM] aszs: ok... i was thinking the maybe the API doesn't distinguish
[1:57 PM] aszs: if item isn't loaded, then the store.get(item, 'foo')
[1:57 PM] aszs: would just remotely load the item if necessary
[1:58 PM] aszs: up to the implementation
[1:58 PM] brian_skinner: okay, i'm back
[1:58 PM] aszs: i mean doesn' t distinguish between items and references
[1:59 PM] brian_skinner: okay, so then store.get(item, 'foo') always returns an item (or a literal -- string, number, date, etc.)
[1:59 PM] aszs: yes
[1:59 PM] aszs: isItem(item) == true
[2:00 PM] aszs: if 'foo' returns an item
[2:00 PM] brian_skinner: and we don't make any distinction between "available items" and "not quite available items"?
[2:00 PM] aszs: hmm, i think so
[2:00 PM] aszs: isItem and isItemAvailable()
[2:00 PM] aszs: need both i think
[2:00 PM] brian_skinner: when would isItemAvailable() be false?
[2:01 PM] aszs: if it isn't loaded or has been deleted
[2:01 PM] brian_skinner: okay, let's ignore the deleted case for a second
[2:02 PM] brian_skinner: so, that API imposes a constraint on the implementations
[2:03 PM] brian_skinner: the implementation has to use the same "item" object to represent the item both before and after the item is loaded
[2:03 PM] aszs: why?
[2:03 PM] brian_skinner: var tolkein = store.get(theHobbit, "author")
[2:04 PM] brian_skinner: if (isItemAvailable(tolkein) { var name = store.get(tolkein, "name") }
[2:04 PM] aszs: isItem(item) { return item instanceof Item || item instanceof Reference; }
[2:04 PM] aszs: oh i see
[2:05 PM] brian_skinner: it's not a problem for any datastore that uses UUIDs or URLs or integers as "item" objects
[2:06 PM] brian_skinner: and also not a problem if you use a JSON-style anonymous object to represent items
[2:06 PM] aszs: well what if there's no isItemAvailable
[2:06 PM] brian_skinner: but i think it might be a problem for datastores that use XML DOM nodes to represent items
[2:06 PM] aszs: is that ok?
[2:07 PM] brian_skinner: if there's no isItemAvailable(), is that the same as saying that any item returned by store.get() is required to be available?
[2:08 PM] brian_skinner: which means store.get() may take a long time to execute, since it may go to the server?
[2:08 PM] aszs: yes or...
[2:08 PM] aszs: user catch exceptions
[2:09 PM] aszs: or change store.get() to return an error somehow
[2:09 PM] brian_skinner: you mean store.get(theHobbit, "author") could return/throw an error if theHobbit isn't an "available" item?
[2:10 PM] aszs: maybe.. ie if( store.get(the, 'authro') == ITEM_NOT_AVAILABLE) ....
[2:10 PM] aszs: or ITEM_DELETED
[2:11 PM] aszs: etc.
[2:11 PM] aszs: maybe some store would fetch automatically
[2:12 PM] aszs: or maybe that could be a flag when creating the store autofetch = true
[2:12 PM] brian_skinner: yup, that would work -- but that makes the GUI code painfully verbose -- you can't use the datastore without constantly doing if() statements to check that you really got a result back
[2:12 PM] brian_skinner: ah, I like autofetch=true
[2:12 PM] brian_skinner: and we could default to autofetch=true
[2:12 PM] brian_skinner: like defaulting to sync=true
[2:13 PM] aszs: so an arg for find? or a global flag for the store?
[2:13 PM] brian_skinner: i was thinking global flag for the store
[2:13 PM] aszs: yes, that seems better
[2:14 PM] brian_skinner: so, if autofetch=false
[2:14 PM] brian_skinner: how does that work
[2:14 PM] brian_skinner: what does the client code look like?
[2:14 PM] aszs: maybe just throws an exception
[2:14 PM] brian_skinner: if( store.get(the, 'authro') == ITEM_NOT_AVAILABLE) {
[2:14 PM] aszs: just like get is currently defined
[2:14 PM] === / Unknown command
[2:14 PM] === /what Unknown command
[2:14 PM] brian_skinner: }
[2:15 PM] aszs: then we don't need to spec it out?
[2:16 PM] brian_skinner: yup, maybe we don't need to spec it out -- I was just curious about what the code would look like in some typical example -- what does the client code do once it finds out that an item is not yet available?
[2:16 PM] aszs: call getByIdentity(item)
[2:16 PM] aszs: ?
[2:17 PM] aszs: or findById() that is
[2:17 PM] brian_skinner: but, getByIdentity() doesn't take an item as a parameter -- it only takes an Identity
[2:17 PM] brian_skinner: right, sorry, findById()
[2:17 PM] brian_skinner: findByIdentity()
[2:17 PM] aszs: well maybe it should be able to take either
[2:17 PM] aszs: don't see any harm in that
[2:17 PM] brian_skinner: so...
[2:18 PM] brian_skinner: var tolkein = store.get(theHobbit, "author")
[2:18 PM] brian_skinner: and then if items are being represented as XML DOM nodes, but tolkein hasn't been loaded?
[2:19 PM] aszs: raise an Error
[2:20 PM] aszs: i think get such continue to raise errors
[2:20 PM] brian_skinner: raise an Error if theHobbit hasn't been loaded, or raise an Error if tolkein hasn't been loaded?
[2:20 PM] aszs: theHobbit
[2:20 PM] brian_skinner: okay, i'm fine with that -- but what if tolkein hasn't been loaded?
[2:20 PM] aszs: what does that mean?
[2:21 PM] aszs: oh
[2:21 PM] aszs: you want to try to load before call get on it?
[2:22 PM] aszs: if (store.isItem(tolkien)) { tolkien = store.findById(tolkien); } //ensure its loaded
[2:22 PM] brian_skinner: should store.get(theHobbit, "author") block on a trip to the server to get tolkien? or do we return (immediately) the Identity of tolkien, or a reference to tolkien?
[2:22 PM] aszs: no its should block
[2:22 PM] aszs: just like we agreeed last week that findbyid blocks
[2:23 PM] brian_skinner: right, so if we don't block, then what does store.get(theHobbit, "author") return
[2:23 PM] brian_skinner: either an Item or an Identity?
[2:23 PM] brian_skinner: so that you can do...
[2:23 PM] brian_skinner: if (store.isItem(tolkien)) { tolkien = store.findById(tolkien); } //ensure its loaded
[2:23 PM] aszs: no it should block
[2:23 PM] aszs: yes
[2:24 PM] brian_skinner: okay, that seems like an okay solution
[2:24 PM] aszs: yup
[2:25 PM] aszs: what to propose that on the wiki page?
[2:25 PM] brian_skinner: but then I think maybe findByIdentity() actually does belong in the dojo.data.Read API, rather than off in dojo.data.Identity, since we're now saying that another dojo.data.Read method (the get method) will sometimes return Identities
[2:26 PM] aszs: its not really returning identities
[2:26 PM] brian_skinner: it's not?
[2:26 PM] brian_skinner: var tolkein = store.get(theHobbit, "author")
[2:26 PM] brian_skinner: if (store.isItem(tolkien)) { tolkien = store.findById(tolkien); } //ensure its loaded
[2:26 PM] brian_skinner: ...
[2:27 PM] aszs: i think findById should work with items
[2:27 PM] aszs: too
[2:27 PM] brian_skinner: you mean, findByIdentity works with unavailable-items
[2:27 PM] aszs: it may or may not be an "Identity"
[2:27 PM] aszs: that up to the implementation
[2:28 PM] aszs: Identity isn't a dojo call
[2:28 PM] aszs: its just a mixin to the store
[2:28 PM] aszs: i mean...
[2:28 PM] aszs: tolkien isn't a dojo.Identity
[2:28 PM] aszs: there maybe some implementation defined Identity object that gets returned
[2:29 PM] aszs: but as long as isItem(tolkien) return true
[2:29 PM] aszs: it doesn't make a difference to the api
[2:31 PM] brian_skinner: hmm... i think my brain is starting to fade -- i'm not crazy about having both (a) the notion of items vs. identities and also (b) the notion of available items vs. not-yet-available items -- i'd rather have just one or the other, but i'm too fried to articulate options/problems
[2:32 PM] aszs: ok
[2:32 PM] aszs: let's wait till next week
[2:33 PM] brian_skinner: okay, sorry i'm not sharper todya
[2:33 PM] brian_skinner: today
[2:33 PM] aszs: no problem
[2:33 PM] brian_skinner: so, other stuff for now?
[2:33 PM] brian_skinner: or adjourn until next week?
[2:33 PM] aszs: i think we're good for today
[2:33 PM] aszs: yes
[2:34 PM] brian_skinner: okay, col
[2:34 PM] brian_skinner: cool
[2:34 PM] aszs: i'll write an email about the REsult
[2:34 PM] aszs: changes
[2:34 PM] brian_skinner: sounds good, thanks