Vector data type (2nd attempt)

J

John G Harris

VK said:
List data type v.2

1) Correct term use (List not Vector): Ray, Harris
2) splice() to insert an element optimization: Ray


<html>
<head>
<title>List constructor</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script>
function List(arr) {
this.$_$ = arr || new Array();
this.length = this.$_$.length;
this.add = List.$add;
this.remove = List.$remove;
this.toString = List.$toString;
}
<snip>

Why don't you give List objects a prototype ?

P.S. what do $add, $remove and so names (starting with $)? Just a
marker of identifiers used only internally (that would be "private"
modifier if existed). Some are using underscores instead (_add,
_remove), but it is really an in-company choice, could be even prvtAdd,
prvtRemove. That is to make the track of vars easier and - if needed -
to have one click conversion to JScript.NET

length needs to be Read Only a lot more than the internal array needs to
be private. If someone changes a List object's length value then you're
scuppered. A length() method accessing the object's array would be a lot
safer.

John
 
M

Matt Kruse

VK said:
List data type v.2
1) Correct term use (List not Vector): Ray, Harris

Do you understand Java? List is an interface. You cannot create a "List"
object.
Further, you only implemented two of its methods, and one of them has a
different argument order. Why even try to make your js look like Java?
2) splice() to insert an element optimization: Ray

How about:
3) Just enhance Array and call it List then: Matt

The following code is much simpler:

----------
Array.prototype.add = function(element,index) {
if (('number'!=typeof index)||(index>=this.length)) {
this.push(element);
}
else {
this.splice(index,0,element);
}
}
Array.prototype.remove = function(index) {
if (('number' != typeof index)||(index >= this.length)) {
return null;
}
else {
if (index<0) {index -= this.length;}
return this.splice(index,1)[0];
}
}
var List = Array;
 
V

VK

John said:
Why don't you give List objects a prototype ?

That is another fully viable option, see the reply by Matt Kruze
length needs to be Read Only a lot more than the internal array needs to
be private. If someone changes a List object's length value then you're
scuppered. A length() method accessing the object's array would be a lot
safer.

Yeh, and have typos all around with length called as property (w/o
parenthesis) :-(
I tried it already in another object. That is not even a programming
issue but an ergonomical one (damn human factor). In this aspect it
seems better then to use VB approach and to have a stay-alone function
for length:
len(myList); // length(myList); ?
That is another thing I'm missing terribly in ECMAScript: an ability to
have compound properties (objects with getter/setter) and respectively
read-only / write-only options for them, not just fields as it is now.
That is a breeze with HTC/XBL. In the regular inline script I once
twisted my mind around of thinking a way to call a function as a
property, but no way. The only trick is available in string context by
overloading toString method.
 
V

VK

Matt said:
List is an interface.
You cannot create a "List" object.

Think of "myArray extends Array implements List", that helps ;-)

How about:
Just enhance Array and call it List then

Another fully viable option.

----------
Array.prototype.add = function(element,index) {
if (('number'!=typeof index)||(index>=this.length)) {
this.push(element);
}
else {
this.splice(index,0,element);
}
}

Array.prototype.remove = function(index) {
if (('number' != typeof index)||(index >= this.length)) {
return null;
}
else {
if (index<0) {index -= this.length;}
return this.splice(index,1)[0];
}
}

var List = Array;
----------
Now, what value does it add? None, really. Under the hood, you're still just
using Array methods. So why not just call it an Array? You're not adding any
value by creating this "List" object.

That is a question of the kind "Why do you need to create class Manager
if it has only one property more than Employee? Simply add that
property to an Employee instance."

Or more generally: "Why do you need OOP hassle? Your custom objects do
not do anything what their supers couldn't, so just augment supers".
:)

Having the prototype way as totally correct option, I need (think I
need, want) a separate object type, not just Array with extra methods.
Array is hadled as a fixed continuum defined by 0 - (length-1) borders.
We can extend this continuum or make "holes" ("gaps") in this continuum
by delete'ing elements.
List (interface) is flexible continuum able to automatically expand and
collapse ("healing the holes") on elements adding/removal.
That seems as enough of behavioral difference for a will to have two
different objects from different constuctors: rather than all existing
and future Array's acting this way or that way depending on what
methods do you apply to them.

Once again: prototype augmentation is definitely and always an option.
 
R

Richard Cornford

VK wrote:
function List(arr) {
this.$_$ = arr || new Array();
this.length = this.$_$.length;
this.add = List.$add;
this.remove = List.$remove;
this.toString = List.$toString;
}
List.$add = function(m,i) {
}
List.$remove = function(i) {
List.$toString = function() {
return this.$_$.toString();
}
P.S. what do $add, $remove and so names (starting
with $)? Just a marker of identifiers used only
internally (that would be "private" modifier if
existed).
<snip>

It would still be more efficient to be creating the methods as
properties of the object's prototype and so having them inherited by the
objects constructed (instead of explicitly assigning them) and then
there is no reason for using (poorly chosen) naming conventions to
discourage people form using them in the context where they are exposed.

Richard.
 
P

Paul

Ray said:
<snip>

As a long time Java programmer and newbie in JavaScript--I wonder--what
kind of value does your Vector add on top of JavaScript's existing
Array? Vector was created in Java because Java's Array is nowhere as
flexible as JavaScript's. Not so with JS's Array.

The methods exposed by your Vector class don't add value to what one
does with JS Array--if you think I'm wrong, I'll be glad to be
corrected.

(and what is with the $add and stuff? They're weird.)
Which leads to ask why Vector and not java.util.List ? Nobody
programming java since version 1.2 should be using Vector. It was
implemented for the reason you pointed out and used becasue there was
nothing better at the time. Promoting the use of a (admitted by Sun)
broken API just doesn't seem like a good idea. As a java programmer he
should know that best practices recommend programming toward interfaces
and not the concrete classes, especially so when it comes the the
Collections API.
If a synchronized list is desired, then the static method
"synchronizedList(List)" should be called on the java.util.Collections
class.

OTOH, it looks like all he is really after is the ability to add an
item at a particualr index and shift the other items, and remove a
particular item and have everything shift back. Which is really much
less than the methods defined in Vector. Seems like the KISS priciple
would dictate just adding these methods to objects of type Array using
the evil prototype.
 
P

Paul

VK said:
Try re-reading the Javadocs.
Vector implements the interface List. List defines the methods. An
interface can not be a derivative of a class.
From the Javadoc for List pertinent to what you are trying to do:
void add(int index, Object element)
Object remove(int index)

Take a look at the documentation of the Collections framework:
http://java.sun.com/j2se/1.4.2/docs/guide/collections/overview.html
From my previous post, Vectors as a rule should be avoided (unless you
are targeting a JVM1.1 or older).
 
P

Paul

VK said:
Matt said:
List is an interface.
You cannot create a "List" object.

Think of "myArray extends Array implements List", that helps ;-)

How about:
Just enhance Array and call it List then

Another fully viable option.

----------
Array.prototype.add = function(element,index) {
if (('number'!=typeof index)||(index>=this.length)) {
this.push(element);
}
else {
this.splice(index,0,element);
}
}

Array.prototype.remove = function(index) {
if (('number' != typeof index)||(index >= this.length)) {
return null;
}
else {
if (index<0) {index -= this.length;}
return this.splice(index,1)[0];
}
}

var List = Array;
----------
Now, what value does it add? None, really. Under the hood, you're still just
using Array methods. So why not just call it an Array? You're not adding any
value by creating this "List" object.

That is a question of the kind "Why do you need to create class Manager
if it has only one property more than Employee? Simply add that
property to an Employee instance."

Or more generally: "Why do you need OOP hassle? Your custom objects do
not do anything what their supers couldn't, so just augment supers".
:)

Having the prototype way as totally correct option, I need (think I
need, want) a separate object type, not just Array with extra methods.
Array is hadled as a fixed continuum defined by 0 - (length-1) borders.
We can extend this continuum or make "holes" ("gaps") in this continuum
by delete'ing elements.
List (interface) is flexible continuum able to automatically expand and
collapse ("healing the holes") on elements adding/removal.
That seems as enough of behavioral difference for a will to have two
different objects from different constuctors: rather than all existing
and future Array's acting this way or that way depending on what
methods do you apply to them.

Once again: prototype augmentation is definitely and always an option.

Since this looks like its getting out of control and Matt was the only
one kind enough to post code, I'm going to offer up the following as
well.
In keeping with the java.util.List inteface, I'm going to give the
size() method instead of length. I am also going to internalize the
methods of the List object. The constructor in this method will copy
the supplied array to prevent its modification (as in VK's posted
code).
I am also adding a few xUnit type tests to validate functionality and
to document usage.
I Hope it helps to clarify what others have been trying to explain.

<html>
<head>
<title>List in JS</title>
</head>

<script type="text/javascript">

function List(srcAry){
this._internAry = new Array();
if(srcAry){
/* Copy supplied array to prevent side effects */
this._internAry = new Array(srcAry.length);
for(var i=0;i<srcAry.length;i++){
this._internAry = srcAry;
}
}
this.add = function(obj,indx){
this._internAry.splice(indx,1,obj)
};
this.remove = function(indx){
return this._internAry.splice(indx,1);
};
this.toString = function(){
return this._internAry.toString();
}
this.size = function(){
return this._internAry.length;
}
}
</script>

<script type="text/javascript">
function assertEquals(msg,val1,val2){
if(val1 != val2){
alert(msg + "\n expected: "+val1+"\nreceived: "+val2);
arguments.callee.failed = +arguments.callee.failed || 0;
arguments.callee.failed++;
}
}
// Tests
var srcAry = new Array('Apples','Oranges','Bananas');
assertEquals("Should be 3 fruit",3,srcAry.length);

var myList = new List(srcAry);
assertEquals("toString test
failed","Apples,Oranges,Bananas",myList.toString());
assertEquals("incorrect size on construction",3,myList.size());

myList.add('Strawberries', 3);
assertEquals("Size failed after adding",4,myList.size());
assertEquals("toString test
failed","Apples,Oranges,Bananas,Strawberries",myList.toString());
assertEquals("Source array modified (bad juju)",3,srcAry.length);

var fruit1 = myList.remove(1);
assertEquals("wrong fruit","Oranges",fruit1);
assertEquals("resize failed after remove",3,myList.size());
assertEquals("toString test
failed","Apples,Bananas,Strawberries",myList.toString());
assertEquals("Source array modified (bad juju)",3,srcAry.length);

var fruit2 = myList.remove(1);
assertEquals("wrong fruit","Bananas",fruit2);
assertEquals("resize failed after remove",2,myList.size());
assertEquals("toString test
failed","Apples,Strawberries",myList.toString());
assertEquals("Source array modified (bad juju)",3,srcAry.length);

if(assertEquals.failed){
alert("tests failed: " + assertEquals.failed);
}else{
alert("All tests passed");
}
</script>
<body>

</body>
</html>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top