8 Replies - 1684 Views - Last Post: 19 June 2012 - 02:34 AM

#1 linuxfreak  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 15-June 12

Javascript question (trait)

Posted 15 June 2012 - 04:31 AM

Hi all,

I have a little problem which I can't solve on my own. The problem is as follows: I've implemented a queue object, which for the simplicity I call q. This object has 2 methods: put(x) and get(), respectively to insert a value into and retrieving from the queue. There's also a third method 'With(constructor)'. This constructor can be Doubling, Incrementing and Filtering. The purpose of the With method is that it should add the constuctor in the inheritance chain of o. Afer the call of the With method the input for q should be doubled, incremented or filtered, depending on the constructor.

This is my implementation so far:
//
function BasicIntQueue(){
  this.l = [];
}


function Filtering(){
}

Filtering.prototype.put = function(x){
  if (x >= 0){
    this.l.unshift(x);
  }
};

function Incrementing(){
}

Incrementing.prototype.put = function(x) {
  this.l.unshift(x + 1);
};

function Doubling(){
}

Doubling.prototype.put = function(x) {
  this.l.unshift(2 * x);
};

BasicIntQueue.prototype.put = function(x) { 
  this.l.unshift(x); 
};

BasicIntQueue.prototype.get = function() { 
  return this.l.pop(); 
};

BasicIntQueue.prototype.With = function(cons){
  var q = Object.create(this);
  
  for(var p in cons.prototype){
    o[p] = cons.prototype[p];
  }
  
  return q;
};




This works fine for the following:
var q2 = new BasicIntQueue();
  q2.put(6);
  q2 = q2.With(Doubling);
  q2.put(7);
  q2.get()// This gives 6 as result
  q2.get()//This gives 14 as result




But when I run the following code, I don't get the correct result:
var q3 = new BasicIntQueue();
  q3.put(13);
  q3 = q3.With(Incrementing).With(Doubling);
  q3.put(21);
  q3.get() //gives 13
  q3.get() //gives 42, where 43 is expected



From here follows that only the last constructor is being executed, where all constructors should be. I have double checked my code and there are no typo's or anything like that.

My question is how can I solve this problem?
More concretely, what am I overseeing to get the correct output? Any suggestions, improvements or how I can do things differently are more then welcome.

Is This A Good Question/Topic? 0
  • +

Replies To: Javascript question (trait)

#2 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 9498
  • View blog
  • Posts: 35,845
  • Joined: 12-June 08

Re: Javascript question (trait)

Posted 15 June 2012 - 06:46 AM

... moving to javascript's forum.
Was This Post Helpful? 0
  • +
  • -

#3 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5907
  • View blog
  • Posts: 12,811
  • Joined: 16-October 07

Re: Javascript question (trait)

Posted 15 June 2012 - 08:35 AM

You first one doesn't work, either. There is no "o" defined... You're returning a new instance q, I'm not sure why.

You seem to want to replace the prototype of the current object with the one passed. I'm not sure how you expect more than one behavior out of that. Or how you could reasonably chain them. If it was just a collection of rules applied to the data before it's pushed, it would be relatively simple. The filter introduces complexity.

Edit: replaced o with q. Works now. But you're still overwriting your rules.

This post has been edited by baavgai: 15 June 2012 - 08:37 AM

Was This Post Helpful? 0
  • +
  • -

#4 linuxfreak  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 15-June 12

Re: Javascript question (trait)

Posted 18 June 2012 - 05:16 AM

View Postbaavgai, on 15 June 2012 - 08:35 AM, said:

You first one doesn't work, either. There is no "o" defined... You're returning a new instance q, I'm not sure why.

You seem to want to replace the prototype of the current object with the one passed. I'm not sure how you expect more than one behavior out of that. Or how you could reasonably chain them. If it was just a collection of rules applied to the data before it's pushed, it would be relatively simple. The filter introduces complexity.

Edit: replaced o with q. Works now. But you're still overwriting your rules.


You are right. The o should be replaced by object; this is the correct code:

//
function BasicIntQueue(){
  this.l = [];
}


function Filtering(){
}

Filtering.prototype.put = function(x){
  if (x >= 0){
    this.l.unshift(x);
  }
};

function Incrementing(){
}

Incrementing.prototype.put = function(x) {
  this.l.unshift(x + 1);
};

function Doubling(){
}

Doubling.prototype.put = function(x) {
  this.l.unshift(2 * x);
};

BasicIntQueue.prototype.put = function(x) { 
  this.l.unshift(x); 
};

BasicIntQueue.prototype.get = function() { 
  return this.l.pop(); 
};

BasicIntQueue.prototype.With = function(cons){
  var q = Object.create(this);
  
  for(var p in cons.prototype){
    q[p] = cons.prototype[p];
  }
  
  return q;
};



Indeed, I am overriding my own methods. The behaviour what is expected, is that all constructor calls should be merged into the object q. For example:

q = q1.With(Doubling).With(Incrementing).With(Filtering);
q1.put(-1);
q1.put(0);
q1.put(-4);
q1.put(3);
q6.get() // Expected result: 2, my output: 0
q6.get() // Expected result: 8, my output: 3



In the above example, everytime the With method is being called the constuctor should be added in the inheritance chain of object q. This is the reason why the current object (the currenct object is BasicIntQueue; this contains 2 methods: put and get) is overriden. The put method should be overridden by the new put method of the constructor. But the
error in my code is that also the constructors method are overridden. So the behaviour of my code is that only the last method With-call is being executed.
Was This Post Helpful? 0
  • +
  • -

#5 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3572
  • View blog
  • Posts: 10,414
  • Joined: 08-June 10

Re: Javascript question (trait)

Posted 18 June 2012 - 05:54 AM

do you actually need to use the prototype? wouldn’t it be easier to store the functions somewhere and pass the value to get through them?
// untested & shortened
function Queue()
{
    this.queue = [];
    this.filters = [];
}
Queue.prototype.get = function() {
    var x = this.queue.pop();
    // depends on the order of the filters
    // increment/double is different from double/increment
    for (var i = 0, l = this.filters.length; i < l; i++) {
        x = this.filters[i](x);
    }
    return x;
};
// and now your filtering functions become simple:
queue.with(function(x) { // increment
    return (x + 1);
}).with(function(x) { // double
    return (2 * x);
});



an alternate way would be to modify the values as they are put in the queue (that only changes the place of the calculation).

This post has been edited by Dormilich: 18 June 2012 - 05:56 AM

Was This Post Helpful? 0
  • +
  • -

#6 linuxfreak  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 15-June 12

Re: Javascript question (trait)

Posted 18 June 2012 - 06:21 AM

This solution is indeed somewhat I need. But it doesn't cover the total problem. The reason for this is in the solution above you assume that there is always a filtering, doubling and incrementing. This is not always the case.

The problem is more dynamic and thereby I would like to predefine how value x should be saved in the queue.
Was This Post Helpful? 0
  • +
  • -

#7 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5907
  • View blog
  • Posts: 12,811
  • Joined: 16-October 07

Re: Javascript question (trait)

Posted 18 June 2012 - 06:30 AM

The way your code is written:
// this
q = q1.With(Doubling).With(Incrementing).With(Filtering);
// is identical to
q = q1.With(Filtering);



Consider:
q[put] = cons.prototype[put];
// same as
q.put = cons.prototype.put;



You are replacing the current function reference with another one. Period. You are NOT somehow stringing them together. There is no chain, there is replacement. Even in an OO language, which Javascript is not, there is no "inheritance chain," only inheritance and the overriding of such. If you want a chain, then the child goes out of its way to call code in the parent.

With each successive munging, you could maintain a reference to call a prior. You'd have to work for it, though. However, your fundamental framework doesn't allow for it. Your replacing prototype is a push. How could you string two pushes together?

I honestly don't believe this a the correct approach. If you wish to go with it, then you might wish to rethink your design. You have a push and pop. What you're really looking to do is have two more functions, filtered and modify value. If those were included in the base, you probably could string them together.

If the goal isn't pseudo OO, but rather results, then I'd let your queue simply support an amendment list.

Since this is kind of a completely different direction from where you're going, here's the code. I'd keep the framework for you own testing...

<html>
<body>
<ol>
<script type="text/javascript">
// our with mods
// we support two methods, filter and adjust
// a mod and contain either or both
var Filtering = { filter: function(x) { return (x < 0); } };
var Incrementing = { adjust: function(x) { return x + 1; } };
var Doubling = { adjust: function(x) { return 2 * x; } };

// the opts to hold current mods
function BasicIntQueue(){  this.l = []; this.opts = []; }
BasicIntQueue.prototype.put = function(x) {
	for(var i in this.opts){
		var opt = this.opts[i];
		if (opt.filter && opt.filter(x)) { return; }
		x = opt.adjust ? opt.adjust(x) : x;
	}
	write("put(" + x + ")"); // just for testing
	this.l.unshift(x); 
};
BasicIntQueue.prototype.get = function() { 
	return this.l.pop(); 
};
BasicIntQueue.prototype.With = function(cons){
	var q = Object.create(this);
	q.opts.unshift(cons); // just add another to the list
	return q;
};

// testing code

function write(s) { document.write("<li>" + s + "</li>"); }

function writeWithExpected(q, expected) {
	var value = q.get();
	write("get() = " + value + ", expected = " + expected);
}

function writeTitle(title) { write("------"); write(title); }


function test1() {
	writeTitle( "test1" );
	var q = new BasicIntQueue();
	q.put(6);
	q = q.With(Doubling);
	q.put(7);
	writeWithExpected(q, 6);
	writeWithExpected(q, 14);
}

function test2() {
	writeTitle( "test2" );
	var q = new BasicIntQueue();
	q.put(13);
	q = q.With(Incrementing).With(Doubling);
	q.put(21);
	writeWithExpected(q, 13);
	writeWithExpected(q, 43);
}

function test3() {
	writeTitle( "test3" );
	var q = new BasicIntQueue();
	q = q.With(Doubling).With(Incrementing).With(Filtering);
	q.put(-1);
	q.put(0);
	q.put(-4);
	q.put(3);
	writeWithExpected(q, 2);
	writeWithExpected(q, 8);
}

test1();
test2();
test3();
write("------");
write("Done");
</script>
</ol>
</body>
</html>



Hope this helps.
Was This Post Helpful? 0
  • +
  • -

#8 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 3572
  • View blog
  • Posts: 10,414
  • Joined: 08-June 10

Re: Javascript question (trait)

Posted 18 June 2012 - 06:40 AM

View Postlinuxfreak, on 18 June 2012 - 03:21 PM, said:

The reason for this is in the solution above you assume that there is always a filtering, doubling and incrementing. This is not always the case.

in that case I wouldn’t use inheritance, but a Factory. But to be honest, I don’t see a difference between
q = q1.With(Doubling).With(Incrementing).With(Filtering);

and
queue.with(function(x) { // increment
    return (x + 1);
}).with(function(x) { // double
    return (2 * x);
});
// same as

/* function definitions ... */

queue.with(increment).with(double);

except that the former creates a new object on every with() call and the latter a new array.

View Postlinuxfreak, on 18 June 2012 - 03:21 PM, said:

The problem is more dynamic and thereby I would like to predefine how value x should be saved in the queue.

as does the array. only these filtering functions are applied, that are present at the time of filtering (be it in the put or the get method).


@baavgai: I think the term "inheritance chain" refers to the prototype chain you build up when doing inheritance in JS.

This post has been edited by Dormilich: 18 June 2012 - 06:43 AM

Was This Post Helpful? 0
  • +
  • -

#9 linuxfreak  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 15-June 12

Re: Javascript question (trait)

Posted 19 June 2012 - 02:34 AM

@baavgai: This is exactly what I was looking for!

I've tested your code and it passed all my tests succesfully. However, your solution is correct, there are a few lines which are acradabra to me.


BasicIntQueue.prototype.put = function(x) {
	for(var i in this.opts){
		var opt = this.opts[i];
		if (opt.filter && opt.filter(x)) { return; }
		x = opt.adjust ? opt.adjust(x) : x;
	}
	write("put(" + x + ")"); // just for testing
	this.l.unshift(x); 
};




In the above code I assume the opts -list is emtpy at initialisation. How can it contain a value?

if (opt.filter && opt.filter(x)) { return; }

If I'm correct this line is a predicate, does this also execute the filter method? I guess so otherwise the code wouldn't return the correct results.

x = opt.adjust ? opt.adjust(x) : x;

I assume here you check if opt.adjust is true/defined. If so, execute it with the value x, otherwise just give x back.

Concerning the constructors (Filtering, Doubling and Incrementing) I know now I was heading for a wrong solution. This was also part of the reason why I was stuck. In stead of returning a function, which should work as a 'peel of an union', I defined a 'void'-function.

Last but not least... Many thanks @baavgai for your time, attention and effort, which you have invested in my problem. And also the others.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1