Posts (page 2)
Ok, so maybe I went a bit overboard with the JavaScript thing before, and then slacked off a whole lot, but I wrote a bunch for you! All.. none of you. But I've returned!
I just want to comment on the development process real quick, and on the importance of understanding the way you're going to implement things before you dive in and implement them.
While I was beginning with the design for Jade in the latter portion of last year, I decided that Views, the things that get displayed on the screen, would have to have a dedicated Div that would hold all it's stuff. I called this the Page Display, because obviously it's the part of the View that gets displayed on the page. Everything would get dumped in that, absolutely everything.
Now, after looking a bit more at the design of NSClipView (for those of you who don't know, Jade is based primarily on OpenStep, hence the NS~ class names), I realized that NSClipView moves its bounds rect to change what part of a NSTableView is shown.
Basically the bounds rect is the rect in the View's own coordinate system that gets drawn to fit within the frame of the view, as it's displayed. For Jade, this doesn't exist; the View's coordinate system is fixed, with (0,0) at the top left corner of the view's page display, and that's just the end of it, so there's no way to move the coordinate system around within the view.
This is relevant for the JadeClipView class because I'm currently clipping simply by moving the content around within the clip view's coordinate system, so that the content's actual position is changed. With NSClipView, on the other hand, the position of the content doesn't change, it's the coordinate system as a whole that moves.
Why is this an issue? Well it means that if you have a TableView (or any other view, really) within a ClipView, the NSTableView would always remain at the same position, and so anything depending on that position can work fine, whereas the JadeTableView will be moving around, and that could cause problems with whatever might depend on those coordinates.
The fix, as far as I can tell, would be to create another Div within the Page Display, perhaps called the Drawing Canvas (not to be confused with the Canvas tag, which might actually be used later in an actual non-html based drawing system), and draw everything into the Drawing Canvas, and move that around to change the bounds rect.
Doing this wouldn't be a huge difficulty, seeing as how it's mainly going to involve replacing all the references to the Page Display when drawing, but thats about 30 or 40 classes at this point. Still, now as major a reworking as the variable privatizing I did last month, which took two or three days of almost non-stop coding and debugging and easily over a thousand manual replacements.
So the moral of the story is that had I planned this out more fully in the beginning, and attempted to keep with fairly strict adherence to OpenStep, I wouldn't have to change 30 draw methods, they would've just been the way I needed to begin with.
No, not the bastard lovechild of Superman and Crystal Method.. Super methods are methods that belong to the class that's being inherited from. It's possible to retail these methods even after they've been re-defined, by providing a nice new method to the Object class prototype.
What we'll do is create a convenience method that will take care of the inheritance for us, and include a little bit of code to make super methods available:
Object.prototype.extend = function( Class ){
Class.apply(this);
var supers = {}; // not "super" because that's a reserved keyword in JS
supers.constructor = this.constructor;
for( var m in prototypical ){
supers[m] = this[m];
}
this.supers = function(){
var dupe = {};
for( var m in supers ){
dupe[m] = supers[m];
}
return dupe; // use private variables and a duplicate to prevent destruction of the original supers object
}
}
With this, we can now extend other classes while retaining the ability to utilize their methods if needed:
function A(){
var foo = "bar";
this.getFoo = function(){ return foo; }
}
function B(){
this.extend(A);
var baz = "bop";
this.getFoo = function(){ return baz; }
}
var b = new B;
alert( b.getFoo() ); // alerts "bop" because we overrode the definition of getFoo
alert( b.supers().getFoo() ); // alerts "bar" because it accesses the supers' method
In this picture, we can see what occurs when we have simply a super object to contain super methods. This would result from the basic extend of Object, in the constructor A. We can see the relationships between the context object, this, which has a super object and some method some method foo, which has access to the context of A, which contains the context object as a variable:
Next we can see the result of an extend of A with a super object to retain the methods for use later:
In this image you can see how we've added the original foo method to the super object, replaced the existing super object with the new one, and also created the new foo method with B.
Incase you're worried that this is smoke and mirrors, and that the super methods simply work on different variables, let's not override anything but instead have a setter method as well:
function C(){
var foo = "bar";
this.getFoo = function(){ return foo; }
this.setFoo = function( newFoo ){ foo = newFoo; }
}
function D(){
this.extend(C);
}
var d = new D;
alert( d.getFoo() ); // alerts "bar", as expected
alert( d.supers().getFoo() ); // alerts "bar" as expected
d.setFoo( "baz" );
alert( d.getFoo() ); // alerts baz, as expected
alert( d.supers().getFoo() ); // alerts baz
So we can see that the supers' methods and the objects methods both have access to the same scope variables, and why shouldn't they? After all, all we did was add a reference to the methods into the supers object. If we don't override the method, then both the object and it's supers object reference the same method, but if we do, we still retain the original method in the supers object.
Also worth noting is that I chose to define the constructor of the supers object as the constructor of the current object. I did this because it's often very convenient to create methods that create new versions of themselves. For instance, if we have a TwoDPoint class that has a method that does something like "new TwoDPoint", and then created a ThreeDPoint class that extends TwoDPoint, the inherited method will still produce a new TwoDPoint, even if it should be creating a new ThreeDPoint. This is avoidable by doing "new this.constructor", which will created a new instance of the same type of object that's executing it, regardless of how deep in an inheritance hierarchy.
Now, if we hadn't set the supers' class, we would have the small problem of not being able to use super methods that have that functionality. Why? Well when you call a super method, the object that's calling it, which also happens to be the context object, is not the object that you're sending the method call to, but rather the supers object. If there are any methods that do "new this.constructor", it will reference the supers object's constructor. If we had not defined it, it would default to Object, and had we defined it as anything other than the current object's constructor, like say Class (which seems reasonable), we wouldn't get a new version of the current object. Both are troublesome! But the fix is elegant and simple.
I hope you learned something from this! Next time I'll be going over class methods and inheritance with them. Have fun, and don't forget to experiment with JavaScript!
Ahh classical inheritance. The bane of any JavaScript developer's existence, at least if they're writing object-oriented code, anyway. Yahoo! lead JavaScript "guru", Douglas Crockford is a huge detractor of classical inheritance, perhaps because it's so poorly understood in JavaScript. Instead he supports his own "parasitic" inheritance. Well I'm here to tell you that classical inheritance isn't bad! It's not even good, it's great! Awesome, even!
I kid, to some extent. Parasitic inheritance isn't all that bad, really.In theory it's exactly like the classical inheritance that I propose, in some fashion anyway. So let's look at parasitic inheritance first. According to Douglas, we can construct an inheritable object oriented system by ignoring the context object entirely, and instead return our own object to return. A simple constructor using this paradigm looks like this:
function MyObject(){
var foo = "bar";
return {
getFoo: function(){
return foo;
}
}
}
var m = MyObject();
alert( m.getFoo() ); // alerts "bar", as expected.
When we call this, the scope variable is created, and a new object literal is returned, with all the fun getter and setter methods we could want to access the variables within that scope. And hey, no need for the "new" keyword either, since this function has a return value! We can take this concept one further to create inheritance:
function Super(){
var foo = 5;
return {
getFoo: function(){
return foo;
}
}
}
function Sub(){
var that = Super();
var bar = 10;
that.getBar = function(){
return bar;
}
return that;
}
var o = Sub();
alert( o.getFoo() ); // alerts 5 as expected
alert( o.getBar() ); // alerts 10, also as expected
So what's wrong with this? Well, nothing really. In fact, it work's exactly like what I advocate, only uglier. There is another add on that Crockford has for this: the "secret" variable, which will hold commonly accessible private variables:
function gizmo(id, secret) {
secret = secret || {};
secret.id = id;
return {
toString: function () {
return "gizmo " + secret.id;
};
};
}
function hoozit(id) {
var secret = {}, /*final*/
that = gizmo(id, secret);
that.test = function (testid) {
return testid === secret.id;
};
return that;
}
var h = hoosit("foo");
alert( h.toString() ); // alerts "gizmo foo"
alert( h.test("foo") ); // alerts true
Now I must say, this way of doing things is very useful. You have shared private variables and you have inheritance. The only problem is that it looks ugly. Now let's explore an alternative. Instead of discarding the context object, let's take full advantage of it. So my first idea, based on Douglas's code there, looks something like this:
function gizmo(id) {
this.id = id;
var foo = "bar";
this.toString = function(){
return "gizmo " + secret.id;
}
}
function hoozit(id) {
gizmo.call( this, id );
this.test = function(testid){
return testid === this.id;
}
this.getFoo = function(){
return foo;
}
}
var h = new hoozit("bar");
alert( h.toString() ); // alerts "gizmo bar", as expected
alert( h.test("bar") ); // alerts true, as expected
alert( h.getFoo() ); // breaks the script, because foo is in a different scope
This works exactly like parasitic inheritance, but it uses the context object (and thus the "new" keyword).
Let's look real quick at why this works as we want it to.
Functions, in JavaScript, are objects too, and have methods associated with them. One of these methods is called "call". Call does something very simple: it calls a the function. Call can take a number of arguments, too, the first of which is the object that you want to use a the context object. That's right, you can apply a function to an object, as if that object were the context object of the function. The arguments after that are simply the arguments you normally would include in the function.
The way this works becomes clearer with visuals. In the case of two separate function calls, things look like this:
When we use call(), however, things look like this:
The context object is the same for, has the methods of, and thus has access to the scopes of both constructor functions. However I'm sure you'll notice that it lacks the shared private variables. with this paradigm, methods created in one constructor cannot directly access the private variables of any scope but it's own. I see no problem with this, assuming you have getter and setter methods for the variables you wish to access, but if you want absolutely must have mutually accessible private variables, no problem:
function gizmo(id, secret) {
var secret = secret || {};
secret.id = id;
secret.foo = "bar";
this.toString = function(){
return "gizmo " + secret.id;
}
}
function hoozit(id) {
var secret = {}; // final
gizmo.call( this, id, secret );
this.test = function(testid){
return testid === this.id;
}
this.getFoo = function(){
return secret.foo;
}
}
var h = new hoozit("bar");
alert( h.toString() ); // alerts "gizmo bar", as expected
alert( h.test("bar") ); // alerts true, as expected
alert( h.getFoo() ); // alerts "bar", as expected
This slight modification, dependent upon the "apply" method, lets you have everything of Douglas's parasitic inheritance, but in a smaller, cleaner form factor.
I personally dislike the use of "secret"; I think that if you're going to completely change the accessibility of a variable, you should redefine it, as it's theoretically no longer the same variable at all. However if you want and need something like "secret", then by all means, use it. In my experience, variable redefinition is very rare, despite the extraordinary scale of the Jade project.
I would also advocate against it because using the "secret" variable introduces the possibility that programmers could insert things into new objects that aren't inherited from others. Now, if a programmer wants to write a bad script, thats fine, but the less opportunity there is to mess things up, the better, especially if it's at less effort, not more.
Hope you enjoyed this. Next time I'll take a look at some more stuff dealing with inheritance. Keep exploring JavaScript; explore what it can do!
Previously I discussed scope in JavaScript, and how these scopes can remain accessible well after their original functions finished executing. Now I'm going to talk about something a little more mysterious: The context object.
What exactly is the context object? Well it's quite simple, really. JavaScript defines a variable, "this", called the context object. This variable cannot be redefined by you, at least not in any traditional fashion, and trying to do so will break your script, but other than that it's completely accessible like any other object, and like other scope variables, exists only within it's particular scope.
The context object is by default the window, and so any function that you create will consider the the window it's context object. For instance:
function testContext(){
alert(this);
}
testContext(); // alerts [object Window], which is the representation of the window object
However, the use of the "new" keyword will call a function with a new context object, so with a slight modification:
function testContext(){
alert(this);
}
new testContext(); // alert [object Object]
The function now executes with a completely new context object. The new keyword will also extract and return the context object when the function completes. The use of the new keyword also eliminates the need for the parentheses when calling zero-argument functions.
var m = new testContext(); // m is now set to the new context object
var n = new testContext; // same result, n set to another new context object
We can attach variables to the context object like any other object as well, when we call the function that creates it:
function MyObject(){
this.foo = "bar";
}
var o = new MyObject;
alert(o.foo); // alerts "bar"
Now recall that if a function is created by another function, it has access to the scope of the function that creates it. This is means we can attach these functions to the context object, and they will behave just like foo in the previous example, when used with the "new" keyword:
function MyObject(){
var foo = "bar";
this.getFoo = function(){
return foo;
}
}
var o = new MyObject;
alert( o.getFoo() ); // still alerts foo, because getFoo was created in, and has access to the context of, the MyObject function
It should be clear now that the use of the context object, along with the "new" keyword, makes it possible to create objects that have what are effectively private variables. The object itself doesn't contain the variables, they exist in the scope of the function that created them, but since that scope is unique for each function call, it pairs up with it's context object in a way that works well for private variables.
I hope you found this useful! Next time I'll go over some more OO JS and address another crucial aspect of any object oriented programming language: Inheritance!
I figured I would share some of my recent explorations into JavaScript's ability to function as an object-oriented programming language with everyone (all none of you that read my blog ;)). I'm going to try to do this in a tutorial like manner, and I'm going to expect that you know something about JavaScript already.
First, and absolutely most important to understand, is JavaScript's scoping rules. Scope is absolutely important in making JavaScript work like a real object-oriented language.
In JavaScript, the creation of variables occurs within a specific scope. The scope is, oddly, enforced by the use of the "var" keyword. When this keyword is not present, a variable is created in the global scope – it's visible everywhere and accessibly by everything. When the "var" keyword is present, the variable exists only within the scope that it's created.
Scopes have a number of different forms. As I mentioned already, one of these is the global scope, which is the script as a whole. Another scopes exist within functions:
var bar = 5;
function doSomething(){
var bar = 10; // a different bar
alert(bar);
}
doSomething(); // alerts 10, from the definition
alert(bar); // original bar, alerts 5
Compare that with this:
var bar = 5;
function doSomething(){
bar = 10; // same bar, redefined
alert(bar);
}
doSomething(); // alerts 10 still
alert(bar); // alerts 10 again due to redefinition of bar
Another important feature of JavaScript, and indirectly of scopes, is that there seems to be some sort of garbage collection that will remove variables and their content when they're no longer accessible by anything (that is, when they are completely isolated from the script and can't affect anything anymore).
This has a very important affect for us. When we talk about scoped variables, in most contexts, when we call a function or create a loop, once we've finished using it, we don't use the variables from inside ever again. And of course we normally couldn't, even if we wanted to, because they exist only within the scope of the loop or function. So the scope is discarded.
However, because scopes, or the variables at least, are discarded only when they're inaccessible, we can prevent this from happening by keeping the variables accessible. For instance, if we have a function that creates functions, if the one that's created has references to variables within the scope of the function that created it, then those variables will still be accessible.
Take for instance this function:
function foo(){
var foo = "bar";
return function(){
alert(foo);
}
}
This function has a variable within it's scope: foo. This variable is accessible to the function that is returned. So continuing from there:
var baz = foo(); // assigns baz to the function returned by foo(). baz is now a function.
baz(); // alerts "bar", since this is what foo was defined as before
From this we can see that even while the function foo() has finished running, it's scope is still accessible to the function baz(). This is because foo() creates a function that can access it's scope, and then returns that function. The scope access remains intact.
I hope this made sense and is enlightening. This simple feature of JavaScript opens a whole lot of doors that otherwise would be closed, and next time I'll go over some of those. The key to good JavaScript is a full understanding of the language, and the best way to get that is by experimenting. Explore!
The Idea
Ok, that's a bit of a mouthful, but why not. Pixel Corps big wig and TWiM/MBW host Alex Lindsay has this dream for a website (in his case a video website) that can look at how you rate videos and compare that to how others rate videos and then when other people with similar rating trends as you rate things highly, you''ll be shown the things that they rated highly. That way you'll only get content that's good. You know it's good because people who like the same things you like said it's good.
Well I think this is a fantastic idea. In fact, I think it should be done for more than just video, it should be done for anything and everything. So I've come up with a basic algorithm for how this could be done. I offer this as an open spec for how this type of system.
Tracking Rating Trends Between Two People
Suppose we have two people, Person 1 and Person 2. To track how these two people's rating patterns compare, four pieces of data are required:
1: The number of times both people agreed that something was good,
2: The number of times both people agreed that something was bad,
3: The number of times Person 1 thought something was good, but Person 2 thought it was bad,
4: The number of times Person 2 thought something was good, but Person 1 thought it was bad.
I'll label these "Good to Both", "Bad to Both", "Good to 1", and "Good to 2", respectively. In order to track this, we need to track how people rated a particular item. When Person 1 rates something, his opinion is recorded. Later when Person 2 rates it, Person 1's opinion is compared to Person 2's new rating, and the appropriate number (Good to Both, Bad to Both, Good to 1, Good to 2) is incremented. This provides data about how any two people's rating patterns compare.
Deciding Who to Track
When a person rates a piece of content, the process of tracking the rating trends is performed for pairs formed by that person and everyone else who's rated this piece of content. If two people have never rated the same item before, there won't be any record of the 4 numbers listed above, so a new record would need to be created. This creates a pairing between the two people. Once that's done, or if the two people already have a pairing, then the record is modified to reflect the new information.
Recommending Content
Once a person rates an item, there is now the potential to recommend that item to everyone that he has pairings with, excluding those that voted on the item (because they've already seen it). To generate a recommendation, we look at those four numbers, and on the way that the person rated it. Assuming the person who is going to make the recommendation is Person 1, we need to look at two numbers.
If Person 1 liked the item, then the important number is Good to 1 + Good to Both. This number is the total number of items that Person 1 thought were good. From this we know what fraction of those Person 2 also thought were good: Good to Both / (Good to 1 + Good to Both). This fraction tells you what proportion of things Person 2 liked, when Person 1 liked them. If this proportion is above a certain user-definable percentage, then you'll be shown the item.
Advising Against Content
Alternatively, we can look at the other number, Bad to 1 + Bad to Both, and look at the proportion of times Person 2 agreed that something was bad: Bad to Both / (Bad to 1 + Bad to Both). This tells us how many times both people agreed disliked a piece of content. When Person 1 rates something as bad, we can determine how likely Person 2 is to also think it's bad, and again if the proportion is above a user-definable percentage, we can specifically prevent the item from being recommended to Person 2.
Anti-Recommendations
A convenient side effect of this way of generating recommendations is that it doesn't matter if Person 1 and 2 completely agree or completely disagree in what's good and what's bad. If Person 2 always likes the things that Person 1 dislikes, the system will recommend what Person 1 dislikes to Person 2, and vice versa if Person 2 always dislikes what Person 1 likes. This occurs because of the thresholding technique.
Suppose Person 1 rates something as good, but the total proportion of things that Person 2 likes of the things that Person 1 likes is very low, below the threshold, that item will be hidden. This makes sense because if the proportion is low, that means Person 2 likes very little of what Person 1 likes. Conversely, if Person 1 rates something as bad, but the proportion of things that Person 2 likes when Person 1 dislikes them is high, then the item is recommended. This also makes sense, because Person 2 usually likes what Person 1 dislikes.
By making recommendations based on number of items that Person 2 likes, relative to the particular rating by Person 1, we can make smart decisions about what is and isn't going to be liked by Person 2. And you can see that it doesn't matter how similar to people are; even people with completely opposite tastes will be good sources of new content: If they have similar tastes, recommend the good items and hide the bad, if they have opposite tastes, recommend the opposite items. The more similar or dissimilar the better, because the proportions of liked items will be closer to 100%.
Database Model
Table 1: Item Opinions
Item ID, User ID, Rating (Good/Bad)
Table 2: Pairings
User 1 ID, User 2 ID, Good to Both, Bad to Both, Good to 1, Good to 2
Table 3: Users
User ID, ..., Threshold
Algorithm
Rate an Item:
for each Item Opinion where Item ID == this item {
if Pairing where (User 1 ID == this user and User 2 ID == this Item Opinion User ID)
or (User 1 ID == this Item Opinion User ID and User 2 ID == this user) does not exist {
create pairing
}
current pairing = Pairing where (User 1 ID == this user and User 2 ID == this Item Opinion User ID)
or (User 1 ID == this Item Opinion User ID and User 2 ID == this user);
if this Rating == Good and this item Opinion Rating == Good {
current pairing good to both ++
} else if this Rating == Bad and this item Opinion Rating == Bad {
current pairing bad to both ++
} else if this Rating == Good and this Item Opinion Rating == Bad {
if this user == current pairing User 1 ID { current pairing good to 1 ++ }
else { current pairing good to 2 ++ }
} else if this Rating == Bad and this Item Opinion Rating == Good {
if this user == current pairing User 1 ID { current pairing good to 2 ++ }
else { current pairing good to 1 ++ }
}
}
Recommending an Item:
for each Pairing where (User 1 ID == this user or User 2 ID == this user) and (User 1 ID and User 2 ID != User ID of current Item Opinions ) {
if this pairing User 1 ID == this user {
if this Rating == Good {
if Good to Both / ( Good to Both + Good to 1 ) > this user threshold { make recommendation }
else { recommend against }
} else {
if Bad to Both / ( Bad to Both + Bad to 1 ) > this user threshold { recommend against }
else { make recommendation }
}
} else {
if this Rating == Good {
if Good to Both / ( Good to Both + Good to 2 ) > this user threshold { make recommendation }
else { recommend against }
} else {
if Bad to Both / ( Bad to Both + Bad to 2 ) > this user threshold { recommend against }
else { make recommendation }
}
}
}
Last week on the TWiT's Futures in Biotech episode 10 Marc Pelletier interviews Dr. Carla Shatz about the human brain. The most fascinating part of the entire interview was a brief part discussing how the brain manages to connect the retina to the visual cortex without ending up completely random. This wasn't the first time I had read about the mechanism – V. S. Ramachandran has at least mentioned it in one of his books – but I had pretty much forgotten.
What happens is that the retina projects nerves to the back of the brain to connect with the occipital lobes to connect into the primary visual cortex. The connects are for the most part random, which is of course bad because
there's no sense to the signals. Waves of activation spread across the retina, neighboring neurons lighting up with electrical activity while more distant ones remain quiet, sending signals back to the visual cortex. The visual cortex then is able to coordinate the input, since even though the receiving neurons seem to randomly light up, they only light up because they neighbor one another in the retina. I suspect it uses some form of Hebbian learning, where neurons that fire simultaneously tend more often to be affected by one another's activation and those that don't are less affected.
To illustrate I offer a simple example using a string of characters. Suppose you have a string that's been scrambled, say " bbeenoooorttt". With information about neighbor status (the first t is next to the start of the string and next to the first o, the r is next to the second o and the first space, the second space is next to second and third t's, etc.) you can reconstruct the original: "To be or not to be". By using the neighbor status of the letters you can very simply say what they are near and thus by knowing what everything is near, you know where everything is.
there are a number of interesting applications that this might have, such as perhaps self building microchips, but the one I'm particularly interested in is artificial neural networks. Self organizing properties would make it significantly easier to design neural networks because it would remove the necessity to design the thing down to the tiniest detail. Instead they could be designed in a broader sense, by function rather than specific wiring. All that's left to do is get cybernetic implants to work properly and we'll have working cyberbrains! But that's another project...
I know this blog has primarily been about my devving, and this post isn't going to be different, but so far I've only focused on Jade and the related projects. I'm going to diverge a bit, now and in my next post, so brace yourselves!
This post is about parallel computations, not in the traditional sense of breaking a problem into multiple independent subtasks and performing them on multiple processors simultaneously, but rather something very different. Instead I mean a system in which the result of computation is independent of the order in which the parts are computed (which does indeed mirror traditional parallel computing), but in which the answer does dependent on what inputs are present. So while it is, in an absolute sense, completely true that traditional parallel computing does result in this, it's only in a strict sense. Sure, if you made a list of all the results of computation, that list would be different depending on which computations were and weren't done, but it's only different as a single whole. No two items are dependent on one another.
I contrast this with what I'm talking about in that there is interdependence; the answer may indeed be a collection of data, but each piece of data is influenced by a number of different inputs, not just one, which is the case with traditional computation. It's more a difference between how input maps to output, I suppose you can say. To modify the parallel computing notation, traditional computing models in general are SISO, single-input/single-output. Whether it's serial, with one instruction being processed at a time, and producing one output, or in parallel, with multiple processors doing multiple things, but each providing a single output at any given time. What I refer to instead could be thought of as MISO or MIMO, multiple-input/single-output or multiple-input/multiple-output. (Interestingly, you could also have a SIMO, single-input/multiple-output model, which creates divergent results through from process, perhaps random mutation, and this would model one of the processes involved in evolution.)
The reason I bring this topic up is because of a particular problem. If you try to simulate a non-SISO computation on an SISO machine, it's relatively easy to do. Because the results are order independent, the calculations can be done granularly in any particular order. But trying to do the reverse, in particular, trying to simulate an SISO computation on an MIMO machine seems to be especially difficult, because an MIMO machine has no instruction cue like an SISO computation does. Serial, and traditionally parallel, computations have some predefined list of instructions, but non-SISO parallel computations have no such predefined list of instructions, so how can you simulate SISO computations on non-SISO machines? It's an interesting problem, especially because it's essentially the question of how the brain, which is massively parallel MIMO device, can create our conscious experience, which seems to have some serialized nature, especially with things like mathematics, which is inherently serial. This difficulty in simulating MIMO computations might even explain why math is such a hard thing to learn.
One possible method, the only one that I've been able to think of, is that you might have a processor that produces a particular output from a particular input, and you might have a second processor that produces the next input, thus creating a feedback loop. This might not necessarily require that the entire input-output flow be mapped before hand, where you already know what outputs lead to what inputs, and aren't really computing anything new. Instead you could set it up so that the simple presence of the output, along with the current state of the processor and the input generator together produce a new input. This way all you'd have to do is have an input generator that depends on the completion of one process, and on the information of which input it previously provided, to generate a new input in a sequential manner. Of course it would be difficult to truly get a process-based system working, perhaps even impossible, since at no does the process really stop performing the computation. Every input to the processor changes the output, and the same goes for the input-generator, so theres a constant feedback.
I think this is a beginning for how it might work, not necessarily the way it does in fact work. But it is a starting point, something to use in creating models of computation.
So JavaScript's this Object Oriented language without classes, as such. Well, in a way it does have classes, because you can use constructor functions that end up behaving like class definitions:
function MyClass(){var foo = 5; // private variablethis.bar = -1; // public variable}
Which is very nice and efficient and I think much better than working with prototypes, which end up creating only public variables, and no unique objects for properties:
function MyClass(){ ... }MyClass.prototype.foo = 5;
MyClass.prototype.bar = {}; // all instances reference this same object! bad bad bad
But how do you inherit the private variables? Well it turns out that it's very easy. JavaScript provides you with the ability to call one function in the context of a specific object, so that the "this" keyword refers to that object. You do it with the "apply()" method of functions. So you can have two constructors, one which calls apply on the other, and you get inherited private variables:
function MyClass(){var foo = 5;this.getFoo = function(){ return foo; }}function OtherClass(){MyClass.apply(this);}var o = new OtherClass;alert( o.getFoo() ); // alerts 5
Now I have to go back and recode everything to take advantage of this. My task:
Turn this:
...this.property = someValue;...
into this:
...var property = someValue;...this.property = function(){ return property; }...
A few thousand lines of code, that's all... It will be fun, I'm sure...
Today I demoed my almost-completed scroll view class to a friend. He immediately discovered a glitch that I hadn't seen. When you moused down on the scrollers anywhere other than the scroller knob, and then moused up outside of the scroller, weird things would happen. Doing this to one of the line buttons (increment or decrement line) would start the autoscrolling feature that should only occur when you maintain a mouse down over the button for a period of time. When you did this over one of the page regions (increment or decrement page), the scroller would seem to do the page down or page up but then get stuck and flicker and do other weird stuff. And when you made the scroller knob proportion small enough, the same autoscroll behavior emerged from the stickiness and flickering from clicking on the page regions.
Well I investigated this phenomena, wondering what I did wrong. What happened was this: When you moused down on the scroller, if you moused down on the knob, the scroller informed the application that all mouse events needed to be directed to the scroller. But this wasn't true when you moused down outside the scroller knob, so if you were to mouse down on the line down button, and then mouse up outside of the scroller, the scroller never got the mouse up. It still thought you were mousing down. Well this was simple to fix, just change it so that the scroller always received the mouse events, regardless of whether you clicked the scroll knob itself or anywhere else.
Ah sweet bliss, I'm thinking. How lovely it is that the solution was so simple! But alas, I created another minor problem: when you moused down on anything other than the knob, and then dragged the mouse around, weird stuff happened! All sorts of flickering and junk. And the scroller didn't scroll up or down a line or page like it should have. Hmm, where could this come from? Well ofcourse the origin wasn't hard to find: because the scroller was receiving all mouse events at all times during a mouse down, it was getting sent mouse drag events even when the line up and down buttons (and page up and down regions) were clicked and then dragged. This normally would drag the scroller knob, so the scroller was drying to drag the scroller knob around even though you never clicked on it. Solution? Don't do anything during a mouse drag unless the scroller knob was clicked.
The moral of the story? Little things can have big impacts. And sometimes solving little problems creates other little problems that weren't there before the solution. Think ahead, and pay attention to the effect that your design decisions will have. It's better to know before hand the consequences of your decisions because you've mapped every possibility out, rather than try to discover them later by trial and error because you weren't looking hard enough when you wrote the code.