Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / February 2007

Tip: Looking for answers? Try searching our database.

Weird behavior on allocation...what's going on?

Thread view: 
Zerex71 - 13 Feb 2007 16:33 GMT
Greetings,

I'm working on an application which will be very math-intensive, and
requires the use of mathematical constructs known as quaternions.
They are basically 4-vectors and that's all you need to know for this
discussion.

Here is the offending code snippet in the main():

       Quaternion q1 = new Quaternion(5.0, 7.0, 6.6, -8.0);
       q1.print();
       Quaternion q2 = new Quaternion(-4.0, -3.0, 2.0, 1.0);
       System.out.println("q1 and q2");
       q1.print();
       q2.print();
       Quaternion q3 = new Quaternion();
       System.out.println("q3 before multiplication");
       q3.print();
       q3 = Quaternion.mul(q1, q2);
       System.out.println("q3 after multiplication");
       q3.print();

Here is the output I get:

quaternion: 5.000 + 7.000i + 6.600j - 8.000k
q1 and q2
quaternion: -4.000 - 3.000i + 2.000j + 1.000k
quaternion: -4.000 - 3.000i + 2.000j + 1.000k
q3 before multiplication
quaternion: 0.000 + 0.000i + 0.000j + 0.000k
q3 after multiplication
quaternion: 0.000 + 0.000i + 0.000j + 0.000k

Can anyone explain to me what I'm missing?  I'm assuming that by doing
new, I get two separate instances, init'd as shown, so that q1 and q2
are not the same thing.  FYI, most of the code in the Quaternion class
is static, so I'm guessing it has to do with some subtle but insidious
misuse of the static keyword in my class definition.  Please help!
Thanks.

Mike
Uwe Plonus - 13 Feb 2007 16:41 GMT
> Greetings,
>
[quoted text clipped - 4 lines]
> misuse of the static keyword in my class definition.  Please help!
> Thanks.

Hi,

it seems that the static causes your problems. Without the class it is
very difficult to show the problems but it seems that the real and
imaginary parts are saved in statics and so only one instance of a
quarternion can exists (what dows not make sense a lot).

Uwe
Zerex71 - 13 Feb 2007 16:48 GMT
> > Greetings,
>
[quoted text clipped - 13 lines]
>
> Uwe

Hi Uwe,

Thanks for your quick reply.  Yes, I have the four coefficients stored
as statics, because I need them for other operations which I want to
be static, so the user can use the class for math operations without
having to have a specific instance (although this is not a hard
requirement).  I just want them to be able to use code like the
following:

q3 = Quaternion.mul(q1, q2)

rather than

q3.mul(q1, q2)

which kind of doesn't make sense because the mul() operation returns a
Quaternion rather than assigning q3's member variables.  But, if after
some discussion I come to the realization that this is a "bad" way to
do things, I will change the implementation.

Thanks for your reply.

Mike
Patricia Shanahan - 13 Feb 2007 16:58 GMT
...
> Thanks for your quick reply.  Yes, I have the four coefficients stored
> as statics, because I need them for other operations which I want to
[quoted text clipped - 4 lines]
>
> q3 = Quaternion.mul(q1, q2)

You can't just stick "static" on a variable without the consequence of
all objects of the class seeing the same value, which does not make
sense for the coefficients.

Your mul implementation should look like:

public static Quaternion mul(Quaternion q1, Quaternion q2){
  Quaternion result = new Quaternion();
  result.t = q1.t*q2.t - q1.x*q2.x -
             q1.y*q1.y - q1.z*q2.z;
  ....
  return result;
}

The code replacing "..." must never reference a coefficient without
qualifying it with q1, q2, or result.

Patricia
Chris Uppal - 13 Feb 2007 18:03 GMT
> q3 = Quaternion.mul(q1, q2)

I think most Java programmers would expect to write that as:

   q3 = q1.mul(q2);

I.e. the mul() operation is an instance method of the Quaternion it is applied
to. If you want the static methods as well, then you can define

   public static Quaternion
   add(Quaternion q1, Quaternion q2)
   {
       return q1.add(q2);
   }

so that the quoted code snippet would also work.

BTW, you said you were considering making your Quaternions immutable.  I think
that's a good idea -- I just wanted to congratulate you on /not/ following the
Sun Quaternion class.  /They/ have chosen to make the things mutable, and in
fact an expression like:

   q1.add(q2);

/changes/ q1 in place to the the sum of the original value of q1, and the
supplied value for q2 (which /isn't/ changed).   I think that's a terrible bit
of design...

(There might have been performance reasons for providing mutating operators
which do change the Quaternion they are applied to, but if so then I don't
think that add() is at all a good name -- addIn() might be better.)

   -- chris
Zerex71 - 13 Feb 2007 19:27 GMT
On Feb 13, 1:03 pm, "Chris Uppal" <chris.up...@metagnostic.REMOVE-
THIS.org> wrote:
> > q3 = Quaternion.mul(q1, q2)
>
[quoted text clipped - 29 lines]
>
>     -- chris

Hi Chris,

Thanks for looking over the code.  As far as your suggestion, writing
it this way:

q3 = q1.add(q2)

is exactly something I don't want to do.  To me, it just looks balky
and I'm not a fan
of doing it that way.  But that's just me; I prefer things to look
more like an expression,
i.e. C = f(A,B) like C = Math.hypot(A,B).  That kind of thing.  I'm
just now getting back
into really learning how to get the most out of the Java language so
there is a lot I want
to investigate.

Unfortunately a lot of what happens to me when I write code, and I
suspect this happens to others,
is that I lay out how I think it should look in the code but then when
I go to call it with real
parameters and variables, I realize it either looks weird, won't
compile, or doesn't seem "clean"
or elegant enough.  Of course, I could be being too picky -- after
all, if I have a function thats
purpose is to add two numbers and return their result, isn't that good
enough, regardless of how
it looks?

Also, as to the question of doing it myself...I realize one of the
cool things about languages,
Java especially, if the portability of packages and classes, and while
I would trust "official"
code from Sun et. al. I am trying to achieve two goals by writing such
a class:

1. Apply what my O'Reilly books and other sources tell me about the
nuances and features of Java to practical,
useable examples
2. Develop real classes that will have function as part of my own
application

I get neither experience from my current software engineering gig and
am none too happy about that,
so I code when I can.

Thank you all for writing.  This is one of the better Abusenet
discussions I've had lately. :)

Mike
Oliver Wong - 13 Feb 2007 20:55 GMT
> On Feb 13, 1:03 pm, "Chris Uppal" <chris.up...@metagnostic.REMOVE-
> THIS.org> wrote:
[quoted text clipped - 51 lines]
> more like an expression,
> i.e. C = f(A,B) like C = Math.hypot(A,B).  That kind of thing.

   I think one reason Chris suggested the q3 = q1.add(q2) syntax is that
it's pretty idiomatic of Java. Strings and BigInteger, for example, both
follow that pattern. So a Java programmer whose is used to using Strings and
BigInteger can quickly guess what the syntax is for your Quaternion classes.

   That said, notice that Chris suggested a way so that both formulations
are available (i.e. q3 = q1.add(q2) would be equivalent to q3 =
Quaternion.add(q1, q2)) with minimal hassle.

   - Oliver
Alex Hunsley - 14 Feb 2007 10:22 GMT
>> On Feb 13, 1:03 pm, "Chris Uppal" <chris.up...@metagnostic.REMOVE-
>> THIS.org> wrote:
[quoted text clipped - 54 lines]
> follow that pattern. So a Java programmer whose is used to using Strings and
> BigInteger can quickly guess what the syntax is for your Quaternion classes.

I've always found that idiom a little annoying in a purist sense,
although you're right in that it is a standard. I think that on first
look, when you're not used to this standard, you might expect an
instance method like q1.add(q2) to actually have an effect on the value
of q1 - but it doesn't (it just returns the result). And I know that
many people do trip up over this assumption, initially.
To me, Quaternion.add(q1, q2) is clearer - a result will be returned.

>     That said, notice that Chris suggested a way so that both formulations
> are available (i.e. q3 = q1.add(q2) would be equivalent to q3 =
> Quaternion.add(q1, q2)) with minimal hassle.

Yup, if space isn't a big limit, I prefer implementing both forms when
writing such a class, and giving the user the choice.
lex
Chris Uppal - 15 Feb 2007 18:08 GMT
> I've always found that idiom a little annoying in a purist sense,
> although you're right in that it is a standard. I think that on first
[quoted text clipped - 3 lines]
> many people do trip up over this assumption, initially.
> To me, Quaternion.add(q1, q2) is clearer - a result will be returned.

That, or something like it, is why I quietly changed the name of the instance
method from
   add()
to
   plus()
in my later example.

   -- chris
Chris Uppal - 14 Feb 2007 19:02 GMT
> Thanks for looking over the code.  As far as your suggestion, writing
> it this way:
[quoted text clipped - 3 lines]
> is exactly something I don't want to do.  To me, it just looks balky
> and I'm not a fan of doing it that way.

I agree that it looks horrible for mathematical expressions.  But then, I think

   q3 = Quaternion.add(q1, q2)

looks horrible too (albeit not as bad).  The only really acceptable syntax is

   q3 = q1 + q2.

But that's not available in Java.

But there are a couple of advantages to using the standard method call syntax
(besides the fact that it /is/ standard).  One is the rather trivial point that
it chains better than the external form.

   q = q1.plus(q2).minus(q3);

rather than

   q3 = Quaternion.add(Quaternion.add(q1, q2), q3);

The more important reason is that it is different semantically -- more
flexible, since it's a message send rather than a mere function call.

For instance, Alex Hunsley's suggestion in this thread, of making Quaternion be
an implementation of a general Field interface (or abstract base class) is only
possible if addition is left to the Field instances themselves (they decide how
they respond to plus()), rather than hardwiring the call by using a static
method.

> Of course, I could be being too picky -- after
> all, if I have a function thats
> purpose is to add two numbers and return their result, isn't that good
> enough, regardless of how
> it looks?

I don't think so (that you're being too picky).  For one thing, if you have
instincts which are telling you that you're not doing things "right", then the
thing to do is listen to them (and train them to work ever better), not to
ignore 'em.   For a second thing, the "look" of the code is anything but a
triviality.  Consider the following for a simple demonstration:

   q = Quaternion.substract(q1, q2);

If that adds the two Quaternions together then you certainly have a "function
that [...] adds two numbers", but it is in no sense "good enough" -- in fact it
is completely evil !

> I get neither experience from my current software engineering gig and
> am none too happy about that,
> so I code when I can.

Good luck. Have fun !

   -- chris
Alex Hunsley - 15 Feb 2007 01:18 GMT
> But there are a couple of advantages to using the standard method call syntax
> (besides the fact that it /is/ standard).  One is the rather trivial point that
[quoted text clipped - 14 lines]
> they respond to plus()), rather than hardwiring the call by using a static
> method.

Surely the Field instances themselves could still handle the operations
statically though...
Chris Uppal - 15 Feb 2007 18:09 GMT
> > For instance, Alex Hunsley's suggestion in this thread, of making
> > Quaternion be an implementation of a general Field interface (or
[quoted text clipped - 4 lines]
> Surely the Field instances themselves could still handle the operations
> statically though...

I'm sorry, but I don't understand what you mean by that.  Could you give an
example ?

   -- chris
Alex Hunsley - 14 Feb 2007 10:21 GMT
>> q3 = Quaternion.mul(q1, q2)
>
[quoted text clipped - 23 lines]
> supplied value for q2 (which /isn't/ changed).   I think that's a terrible bit
> of design...

Aargh! I didn't know the sun version did that. Naughty sun.
I think it's much easier to go the immutable way, rather than mutable,
when you then end up writing defensive methods in order to be sure your
code is robust, even when used by third parties....

> (There might have been performance reasons for providing mutating operators
> which do change the Quaternion they are applied to, but if so then I don't
> think that add() is at all a good name -- addIn() might be better.)

The minefield of method names and implied information!
Oliver Wong - 13 Feb 2007 16:48 GMT
> Greetings,
>
[quoted text clipped - 35 lines]
> misuse of the static keyword in my class definition.  Please help!
> Thanks.

   We would probably want to see the source code for
Quaternion.mul(Quaternion,Quaternion).

Additional info which may help:

   * Did you write the Quaternion class, or did a 3rd party write it?
   * If you know, are instances of the Quaternion immutable?

   - Oliver
Oliver Wong - 13 Feb 2007 16:50 GMT
>> Greetings,
>>
>> I'm working on an application which will be very math-intensive, and
>> requires the use of mathematical constructs known as quaternions.
>> They are basically 4-vectors and that's all you need to know for this
>> discussion.

[...]

>    * Did you write the Quaternion class, or did a 3rd party write it?

   In either case, have you considered using Sun's Quaternion
implementation?

http://java.sun.com/products/java-media/3D/forDevelopers/J3D_1_3_API/j3dapi/java
x/vecmath/Quat4f.html

http://java.sun.com/products/java-media/3D/forDevelopers/J3D_1_3_API/j3dapi/java
x/vecmath/Quat4d.html


   - Oliver
Zerex71 - 13 Feb 2007 17:13 GMT
> >> Greetings,
>
[quoted text clipped - 13 lines]
>
>     - Oliver

No, because I want and need to do this myself to understand everything
about them.
I would trust Sun, but generally speaking I do not trust other
people's code - even if it supposedly works,
I still find that oftentimes they are sloppy in their style and not as
elegant as it can be.  Besides, I've
trust Microsoft for years now and am getting tired of that
relationship. :)

Mike
Oliver Wong - 13 Feb 2007 17:32 GMT
>> >> Greetings,
>>
[quoted text clipped - 20 lines]
> trust Microsoft for years now and am getting tired of that
> relationship. :)

   No offense, but if their implementation of Quaternion works, and yours
doesn't, then maybe the level of elegance of their code is higher than the
bar you've set.

   If you wish to learn Java programming, then it makes sense to write your
own versions of stuff, for the practice of it. But you'll have to one day
eventually learn to deal with other people's code, because software nowadays
is too complex for a person to implement alone. And then there's also the
principle of "don't reinvent the wheel".

   - Oliver
Zerex71 - 14 Feb 2007 15:18 GMT
> >> "Oliver Wong" <o...@castortech.com> wrote in message
>
[quoted text clipped - 36 lines]
>
>     - Oliver

Oliver,

I should have told you that I've been programming Java off and on for
several years and have been
a software engineer for about 16 years now.  I think I know how to
deal with other people's code,
and most of the time, it's pretty lousy, so I'm fine with the bar I've
set, thank you very much. :)

Mike
Alex Hunsley - 13 Feb 2007 18:21 GMT
>>>> Greetings,
>>>> I'm working on an application which will be very math-intensive, and
[quoted text clipped - 13 lines]
> No, because I want and need to do this myself to understand everything
> about them.

It's a good practice to write a Quaternion class yourself then.
Two things:

1) to get the most out of this, get poeple (e.g. in this group) to
review your code once you've finished - you may get useful feedback,
like has already happend

2) it's worth testing your code actually works once you've finished. For
example, writing unit tests to see if things behave 'normally' when you
do quaternion arithmetic. This is where knowing properties of
complex/quaternion arithmetic come in very handy. For example, if you
know de Moivre's rule and all that, you can write some tests to check
your quaternion multiplication is behaving sensibly in certain
circumstances, and so on.

> I would trust Sun, but generally speaking I do not trust other
> people's code - even if it supposedly works,
> I still find that oftentimes they are sloppy in their style and not as
> elegant as it can be.  

A lot depends on how trustworthy the publisher is, and widely used the
code is. For example, I know that Jakarta Common's HTTPClient is used
widely and that means something.

lex
Zerex71 - 13 Feb 2007 16:51 GMT
> > Greetings,
>
[quoted text clipped - 45 lines]
>
>     - Oliver

Oliver,

Here's the class in its entirety...still under development:

package angle;

/**
* @author mfeher
*
*/
public class Quaternion
{
   // Methods
   // Constructors
   Quaternion() {
       q0 = 0.0;
       q1 = 0.0;
       q2 = 0.0;
       q3 = 0.0;
   }

   Quaternion(double q, double qi, double qj, double qk) {
       q0 = q;
       q1 = qi;
       q2 = qj;
       q3 = qk;
   }

   // Conversion methods
   // Method to convert a quaternion to Euler angles
   static EulerAngles quat2euler(Quaternion q) {
       // First we need to convert to a DCM representation
       Matrix3x3D DCM = new Matrix3x3D();
       DCM = Quaternion.quat2dcm(q);
       // Now, using the DCM, extract the Euler angles in radians
       double rollRad = Math.atan(DCM.item(1, 2) / DCM.item(2, 2));
       double pitchRad = Math.asin(-1*DCM.item(0,2));
       double yawRad = Math.atan(DCM.item(0, 1) / DCM.item(0, 0));

       // Convert the Euler angles in radians to degrees and store
them
       Angle roll = new Angle(Angle.rad2deg(rollRad));
       Angle pitch = new Angle(Angle.rad2deg(pitchRad));
       Angle yaw = new Angle(Angle.rad2deg(yawRad));
       // Set the resultant Euler angles
       EulerAngles euler = new EulerAngles(roll, pitch, yaw);
       return euler;
   }

   // Defined mathematical operations
   // All of these operations are static so they can be used without
having
   // *this* quaternion possess real values
   static Quaternion add(Quaternion qa, Quaternion qb) {
       // This method performs the defined operation of addition on
two quaternions
       // i.e. qc = qa + qb
       Quaternion qc = new Quaternion();
       qc.q0 = (qa.q0 + qb.q0);
       qc.q1 = (qa.q1 + qb.q1);
       qc.q2 = (qa.q2 + qb.q2);
       qc.q3 = (qa.q3 + qb.q3);
       return qc;
   }

   static Quaternion neg(Quaternion q) {
       // This method performs the defined operation of negation of a
quaternion
       // i.e. q_neg = neg(q)
       Quaternion q_neg = new Quaternion();
       q_neg.q0 = -1*q.q0;
       q_neg.q1 = -1*q.q1;
       q_neg.q2 = -1*q.q2;
       q_neg.q3 = -1*q.q3;
       return q_neg;
   }

   static Quaternion sub(Quaternion qa, Quaternion qb) {
       // This method performs the defined operation of subtraction
on two quaternions
       // i.e. qc = (qa - qb)
       Quaternion qc = new Quaternion();
       qc.q0 = (qa.q0 - qb.q0);
       qc.q1 = (qa.q1 - qb.q1);
       qc.q2 = (qa.q2 - qb.q2);
       qc.q3 = (qa.q3 - qb.q3);
       return qc;
   }

   static Quaternion mul(Quaternion qa, Quaternion qb) {
       // This method performs the defined operation of
multiplication on two quaternions
       // i.e. qc = (qa * qb)
       // Later on we may implement 3x3 matrix operations whereby we
can
       // use those appropriately rather than doing it "directly"
like we do
       // here (the less elegant but no less accurate approach).
       Quaternion qc = new Quaternion();

       qc.q0 = (qa.q0*qb.q0 - qa.q1*qb.q1 - qa.q2*qb.q2 -
qa.q3*qb.q3);
       qc.q1 = (qa.q0*qb.q1 + qa.q1*qb.q0 + qa.q2*qb.q3 -
qa.q3*qb.q2);
       qc.q2 = (qa.q0*qb.q2 + qa.q2*qb.q0 + qa.q3*qb.q1 -
qa.q1*qb.q3);
       qc.q3 = (qa.q0*qb.q3 + qa.q3*qb.q0 + qa.q1*qb.q2 -
qa.q2*qb.q1);

       // Note that we can use this method to multiply vector
quaternions, which
       // simply means that the scalar parts of such vectors are zero
(i.e. we
       // don't need a separate multiplication method to achieve
this).
       return qc;
   }

   static Quaternion inv(Quaternion q) {
       // This method returns the inverse of a given quaternion
       // i.e. q_inv = q^-1
       Quaternion q_inv = new Quaternion();
       return q_inv;
   }

   static Quaternion div(Quaternion qa, Quaternion qb) {
       // This method performs the defined operation of division on
two quaternions
       // i.e. q_div = qa/qb
       Quaternion q_div = new Quaternion();

       // First, take the inverse of qb, the denominator
       Quaternion qb_inv = Quaternion.inv(qb);

       // Now multiply it by the numerator
       q_div = Quaternion.mul(qa, qb_inv);
       return q_div;
   }

   static Quaternion conj(Quaternion q) {
       // This method returns the conjugate of a given quaternion
       // i.e. q_conj = ~q
       Quaternion q_conj = new Quaternion();
       return q_conj;
   }

   static Quaternion unit(Quaternion q) {
       // This method returns the unit quaternion of a given
quaternion
       // i.e. q_unit = |q|
       Quaternion q_unit = new Quaternion();
       return q_unit;
   }

   static double index(Quaternion p, Quaternion q) {
       // Method to calculate the index of quaternions.  If the
quaternions are
       // right quaternions, then the index of a right quaternion is
the axis of
       // the quaternion scaled by the ratio of lengths.
       return 0.0;
   }

   static double scalar(Quaternion q) {
       // Method to determine the scalar part of a quaternion
       // Part of the representation in rectangular (Cartesian)
coordinate
       return q0;
   }

   static Vector right(Quaternion q) {
       // Method to determine the right part of a quaternion
       // Part of the representation in rectangular (Cartesian)
coordinate
       Vector right = new Vector(q1, q2, q3);
       return right;
   }

   static void tensor(Quaternion q) {
       // Method to determine the tensor part of a quaternion
       // Part of the representation in polar coordinates
   }

   static void versor(Quaternion q) {
       // Method to determine the versor part of a quaternion
       // Part of the representation in polar coordinates
   }

   // Later on we may add the "scalar" and "vector" getters for a
quaternion.

   // TODO: Change to regular DCM when we implement that
   static Matrix3x3D quat2dcm(Quaternion q) {
       // Method to convert a given quaternion into a DCM
       Matrix3x3D DCM = new Matrix3x3D();  // Change to regular DCM
when we implement that
       DCM.array[0][0] = ((q.q0 * q.q0) + (q.q1 * q.q1) - (q.q2 *
q.q2) - (q.q3 * q.q3));
       DCM.array[0][1] = 2 * ((q.q1 * q.q2) + (q.q0 * q.q3));
       DCM.array[0][2] = 2 * ((q.q1 * q.q3) - (q.q0 * q.q2));
       DCM.array[1][0] = 2 * ((q.q1 * q.q2) - (q.q0 * q.q3));
       DCM.array[1][1] = ((q.q0 * q.q0) - (q.q1 * q.q1) + (q.q2 *
q.q2) - (q.q3 * q.q3));
       DCM.array[1][2] = 2 * ((q.q2 * q.q3) + (q.q0 * q.q1));
       DCM.array[2][0] = 2 * ((q.q1 * q.q3) + (q.q0 * q.q2));
       DCM.array[2][1] = 2 * ((q.q2 * q.q3) - (q.q0 * q.q1));
       DCM.array[2][2] = ((q.q0 * q.q0) - (q.q1 * q.q1) - (q.q2 *
q.q2) + (q.q3 * q.q3));
       return DCM;
   }

   // Lastly, we implement the all-important rotate method - but we
will need
   // a 3D vector class to do this
   Vector rot(Quaternion q, Vector v_old) {
       // Rotate a vector using defined quaternion transformation
       Vector v_new = new Vector();
       // Perform transformation operations
       // v_new = q * v_old * q_inv
       return v_new;
   }

   // Getter methods
   double q0() { return q0; }
   double q1() { return q1; }
   double q2() { return q2; }
   double q3() { return q3; }

   // Print/inspect methods
   // May want to implement toString here instead
   void print() {
       // Method to print out this quaternion.
       // We need some simple handling based on the sign of each
component of
       // the quaternion.
       String s0, s1, s2, s3;
       s0 = String.format("%.3f", q0);

       if (q1 < 0)
       {
           s1 = String.format("- %.3f", -1*q1);
       }
       else
       {
           s1 = String.format("+ %.3f", q1);
       }

       if (q2 < 0)
       {
           s2 = String.format("- %.3f", -1*q2);
       }
       else
       {
           s2 = String.format("+ %.3f", q2);
       }

       if (q3 < 0)
       {
           s3 = String.format("- %.3f", -1*q3);
       }
       else
       {
           s3 = String.format("+ %.3f", q3);
       }

       String q = String.format("quaternion: %s %si %sj %sk", s0, s1,
s2, s3);
       System.out.println(q);
   }

   // Attributes
   private static double q0;
   private static double q1;
   private static double q2;
   private static double q3;
}
Alex Hunsley - 13 Feb 2007 17:07 GMT
> Oliver,
>
> Here's the class in its entirety...still under development:
>
> package angle;
[snip]

A little feedback on your code:

* it's conventional to put your member variables right at the top of the
class
* consider making your Quaternion class immutable. In other words, once
a Quat. is made, it cannot be changed. To do this, make your i, j, k etc
member vars be "public final". Once you do this, you could get rid of
getters.
Immutable objects also remove the chance to mangle objects that other
bits of code are depending on not changing.

lex
Zerex71 - 13 Feb 2007 17:29 GMT
> > Oliver,
>
[quoted text clipped - 16 lines]
>
> lex

Thanks to everyone who helped - your suggestions will be taken under
consideration!  I didn't even consider making them immutable.  You're
right though, because now that I think about it, I can declare an
instance of a quaternion and like most doubles, you never really need
to change a particular double (I can always allocate another one as
needed).  There's a lot of good suggestions here that I will use.  I'm
just glad I wasn't as far off as I originally expected -- I'm having
the double "challenge" of implementing the mathematics behind this
class as well as dealing with the nuances of the Java language.  But
it will be so worth it when I'm finished.

Mike
Alex Hunsley - 13 Feb 2007 18:16 GMT
> Thanks to everyone who helped - your suggestions will be taken under
> consideration!  I didn't even consider making them immutable.  You're
[quoted text clipped - 6 lines]
> class as well as dealing with the nuances of the Java language.  But
> it will be so worth it when I'm finished.

Glad to help. I'm interested in seeing your final class when you're
finished too.
Patricia Shanahan - 13 Feb 2007 16:49 GMT
> Greetings,
>
[quoted text clipped - 37 lines]
>
> Mike

The code being static may not be a problem, but from your results I'm
guessing that the variables representing the components of the
quaternion are also static, so that at any given time all Quaternion
objects have the same components, the most recently created or
calculated values. For example, the "new Quaternion()" makes the
components zero, and the multiplication is (0,0,0,0)*(0,0,0,0).

If I'm right, you need to remove "static" from those variables. You may
also need to change some methods to either be non-static or to avoid
using "this", explicitly or implicitly.

Patricia
Alex Hunsley - 13 Feb 2007 17:02 GMT
> Greetings,
>
> I'm working on an application which will be very math-intensive, and
> requires the use of mathematical constructs known as quaternions.
> They are basically 4-vectors and that's all you need to know for this
> discussion.

All praise Hamilton, for ijk=-1!

> Here is the offending code snippet in the main():
>
[quoted text clipped - 27 lines]
> is static, so I'm guessing it has to do with some subtle but insidious
> misuse of the static keyword in my class definition.  Please help!

Yup. Sounds like you've defined member variables in your Quaternion
class as static, which is not going to behave the way you want (as you
noticed). The 'new' keyword does indeed make a new object, but 'static'
can be used to cause different objects to all share one piece of data.

In other words, your code is probably like this:

public class Quaternion {
   private static float real;
   private static float i;
   private static float j;
   private static float k;

   public Quaternion(float real, float i, float j, float k) {
     this.i = i; // or you could write Quaternion.i = i
     this.j = j;
     this.k = k;
     this.real = real;
   }
}

which isn't correct.
To fix, just remove the 'static' from your member vars:

   private float real;
   private float i;
   private float j;
   private float k;

Static member vars can be used for holding data *that applies to your
whole class* or *data which you know is common to every instance you
will make*.

For example, you might have a static member variable recording how many
Quaternion objects had been made so far (and you increment this value in
the constructor), so your code would look like:

public class Quaternion {
   private float real;
   private float i;
   private float j;
   private float k;

   private static int numQuaternions = 0;

   public Quaternion(float real, float i, float j, float k) {
     this.i = i; // or even Quaternion.i = i
     this.j = j;
     this.k = k;
     this.real = real;

     Quaternion.numQuaternions++; // we just made another
   }

   // note that this method has to be static in order to
   // access the static membar variable, and hence you should
   // call it using Quaternion.getNumQuaternionsMade()
   public static int getNumQuaternionsMade() {
     return numQuaternions;
   }
}

(Note that this isn't thread safe, but that's another topic.)

HTH,
lex
Alex Hunsley - 14 Feb 2007 10:16 GMT
> Greetings,
>
> I'm working on an application which will be very math-intensive, and
> requires the use of mathematical constructs known as quaternions.
> They are basically 4-vectors and that's all you need to know for this
> discussion.
[snip]
Btw Zerex, here's a nice little idea...
If you can find a Java mathematical expression parser (e.g.
http://www.singularsys.com/jep/), but one that supports arithmetic on
arbitrary systems that you provide classes for (e.g. Quaternion), you
could also hook that up.
The end result is that your class could provide functionality which
would let the user evaluate an arbitrary algebraic string expression, e.g.:

 Hashtable values = new Hashtable();
 values.put("a", new Quaternion(1, 2, 3, 4.6));
 values.put("b", new Quaternion(0, 0, -1, 3));
 values.put("c", new Quaternion(-10.4, 0, 0, 4));

 Quaternion result = Quaternion.evaluate("(a*b - c^2)/2");

Or, of course, you (or I) could write an arbitrary expression evaluator
ourselves (or modify an existing one, if possible). The key to writing
it would be that the end-user provides a class (e.g. Quaternion) that
implements an interface, 'AlgebraicField', which means that add, sub,
mult and divide methods are provided... (of course, this interface's
method would be taking Objects and nothing more specific, in order to
remain generalised). Then just turn the expression into a prefix stack
for evaluation, evaluate, and voila!

lex
Lew - 14 Feb 2007 20:09 GMT
>  Hashtable values = new Hashtable();
>  values.put("a", new Quaternion(1, 2, 3, 4.6));
>  values.put("b", new Quaternion(0, 0, -1, 3));
>  values.put("c", new Quaternion(-10.4, 0, 0, 4));

For my edification, why did you choose Hashtable over other Map implementations?

- Lew
Oliver Wong - 14 Feb 2007 21:27 GMT
>>  Hashtable values = new Hashtable();
>>  values.put("a", new Quaternion(1, 2, 3, 4.6));
[quoted text clipped - 3 lines]
> For my edification, why did you choose Hashtable over other Map
> implementations?

   I'm guessing it's for the O(1) lookup, and 'cause order doesn't really
need to be preserved. These are names of variables used in the expression
that appears later: "(a*b - c^2)/2".

   - Oliver
Daniel Pitts - 14 Feb 2007 22:32 GMT
> >>  Hashtable values = new Hashtable();
> >>  values.put("a", new Quaternion(1, 2, 3, 4.6));
[quoted text clipped - 9 lines]
>
>     - Oliver

Whats that have to do with Map vs Hashtable?  If the question was "Why
aren't you using SortedMap", then your response makes sense. Ohwell.

Map<String, Quaternion> values = new HashMap<String, Quaternion>();

values.put("a", new Quaternion(1, 2, 3, 4.6));
values.put("b", new Quaternion(0, 0, -1, 3));
values.put("c", new Quaternion(-10.4, 0, 0, 4));
Oliver Wong - 15 Feb 2007 15:42 GMT
>> >>  Hashtable values = new Hashtable();
>> >>  values.put("a", new Quaternion(1, 2, 3, 4.6));
[quoted text clipped - 17 lines]
> values.put("b", new Quaternion(0, 0, -1, 3));
> values.put("c", new Quaternion(-10.4, 0, 0, 4));

   I was focusing on the keywords "other implementations" in "other Map
implementations". AFAIK, the other main Map implementation (TreeMap) doesn't
provide O(1) lookup, and the rests are for "special" situations (e.g.
EnumMap, WeakHashMap, ConcurrentHashMap, IdentityHashMap, etc.)

   - Oliver
Daniel Pitts - 15 Feb 2007 18:03 GMT
> >> "Lew" <l...@nospam.lewscanon.com> wrote in message
>
[quoted text clipped - 28 lines]
>
>     - Oliver

You do realize there is a different between the Hashtable and HashMap
classes, right?  I believe that is what Lew was asking about.
Hashtable is retained for backward compatibility only.
Oliver Wong - 15 Feb 2007 18:53 GMT
>> >> "Lew" <l...@nospam.lewscanon.com> wrote in message
>>
[quoted text clipped - 32 lines]
> classes, right?  I believe that is what Lew was asking about.
> Hashtable is retained for backward compatibility only.

   Oops. I missed that part.

   - Oliver
Chris Uppal - 15 Feb 2007 19:17 GMT
>     I was focusing on the keywords "other implementations" in "other Map
> implementations". AFAIK, the other main Map implementation (TreeMap)
> doesn't provide O(1) lookup, and the rests are for "special" situations
> (e.g. EnumMap, WeakHashMap, ConcurrentHashMap, IdentityHashMap, etc.)

I think the issue was: why use the ancient, and largely superseded,
implementation of Map called Hashtable, instead of its (mostly) equivalent
replacement, HashMap ?

(Same slight irritation as seeing Vector used where ArrayList would be better.)

   -- chris
Alex Hunsley - 15 Feb 2007 22:42 GMT
>>     I was focusing on the keywords "other implementations" in "other Map
>> implementations". AFAIK, the other main Map implementation (TreeMap)
[quoted text clipped - 6 lines]
>
> (Same slight irritation as seeing Vector used where ArrayList would be better.)

Actually, I was still in J2ME mode when I wrote that post - hence
Hashtable, which is available, whereas Hashmap ain't. (Similarly,
there's no ArrayList - you have to use Vector.)

>     -- chris
Lew - 16 Feb 2007 01:23 GMT
> Actually, I was still in J2ME mode when I wrote that post - hence
> Hashtable, which is available, whereas Hashmap ain't. (Similarly,
> there's no ArrayList - you have to use Vector.)

Aha!

- Lew
Zerex71 - 22 Feb 2007 19:36 GMT
In my continued question to implement some code, I ran across another
question.

I have a Vector class which is intended for use as a true, real vector
(mathematical), not the misnamed kind of "collection"
class that it usually it refers to.  It is subclassed from the generic
Matrix class which contains the actual data members
(a 1,3 matrix storing three doubles in an array called, oddly enough,
"array").  Whenever I perform an operation that modifies
the values of Matrix.array, I want Vector to also have its attributes
(double x,y,z) to also be updated.

Here's the catch: Much of what I'm doing with the Vector right now is
static, so I'm only using the class to perform operations
for me, not so much to store content (although I will be using it for
that just as much very soon).  My question is, if I invoke
Vector.operation() which returns another Vector, how does the
underlying array even get set?  How do x,y, and z get updated if I
am using it statically?

Here's an example:

v_new = Vector.scale(v_old, k);  // Standard scaling of a vector by a
length factor k
...
a = v_new.x(); // These are getter methods named identical to their
member variables
b = v_new.y();
c = v_new.z();

Also,

class Matrix {
   double array[][];
...
}

class Vector extends Matrix {
   double x;  // Any time the underlying array[][] elements get
updated, these should be too
   double y;
   double z;
...
}

This implementation may be overkill, but I like the elegance of taking
this approach.  Also,
the x,y,z and their corresponding getters are really for convenience -
"x" is a lot easier
to type than "array[0][0]".  That sort of thing.

I'm sure I'm not explaining this fully but I think you get the idea.
Discuss!
Lew - 22 Feb 2007 19:45 GMT
A new topic deserves a new thread.

> I have a Vector class which is intended for use as a true, real vector
> (mathematical), not the misnamed kind of "collection"
[quoted text clipped - 35 lines]
> "x" is a lot easier
> to type than "array[0][0]".  That sort of thing.

Don't have instance variables for x, y and z. Define the methods in terms of
the underlying, inherited array.

  public double x()
  {
    return array [0] [0];
  }

- Lew
Zerex71 - 22 Feb 2007 21:02 GMT
> A new topic deserves a new thread.
>
[quoted text clipped - 47 lines]
>
> - Lew

Your last suggestion I can live with.  I just wanted to use the x, y,
and z names as ways to reference.
That still leaves the question of how the array gets updated if I am
using the class in a static fashion
i.e. not setting its individual members to particular values.  As to
the former suggestion, it's a continuation
of an earlier topic, so sorry.
Lew - 22 Feb 2007 22:28 GMT
Lew wrote:
>> Don't have instance variables for x, y and z. Define the methods in terms of
>> the underlying, inherited array.
[quoted text clipped - 3 lines]
>>      return array [0] [0];
>>    }

> Your last suggestion I can live with.  I just wanted to use the x, y,
> and z names as ways to reference.
> That still leaves the question of how the array gets updated if I am
> using the class in a static fashion
> i.e. not setting its individual members to particular values.  

Use an appropriate setBlah( double val ) method.

Or perhaps setBlah( double val, int row, int col ).

This business of hiding all attributes behind accessor methods is quite
powerful, at the cost of verbosity. A method pair "setX()" and "getX()" need
never reference an actual instance variable "x" within the black box. They
only need to present to API clients the view of "x" as an attribute.

Don't use static members unless you really intend the value to be what it is
for the entire class. If your analytical model says, "I can have two Vectors,
call them 'va' and 'vb', and they can contain separate values, and not be
equal in value to each other", then the model requires that the "values" for
Vectors be instance-level.

While you're at it, you will want to override the Object methods equals() and
hashCode(), in a consistent manner.

You also face the decision of whether to make Matrix instances immutable, in
effect "read-only" after construction. There are distinct benefits to doing
so, but it complicates objects that support calculations.

Joshua Bloch covers these overrides and immutability admirably in his book
/Effective Java/, and there are many articles on these topics. GIYF. So are
IBM DeveloperWorks and Sun's Java sites.

P.S., in UMLish diagrams and class design documentation, I model accessor and
mutator methods as attributes, not methods. At times some of my colleagues
want to change the design docs to match the physical implementation as
methods. This is, of course, working the wrong way around.

- Lew
Zerex71 - 23 Feb 2007 14:36 GMT
> Lew wrote:
> >> Don't have instance variables for x, y and z. Define the methods in terms of
[quoted text clipped - 42 lines]
>
> - Lew

Hi Lew,

The thing with using the static functionality is that it's an area of
use that I want to investigate.
Not only am I developing an application but I'm also expanding my
thoughtview of the language.  To that
end, I am learning how best to take advantage of static vs. non-
static.  In other words, I often have
the need for a class to do some utility on behalf of some other code,
but not necessarily to have
an instance, and yet, the class can bind up instance-based methods and
attributes in one place (if any
of this makes any sense).

In other words, I want Vector to represent individual instances of
unchangeable values (I don't modify a vector
but will instead, operate on it to produce another result/instance),
but I also want Vector to have operations
that can be used without requiring an instance (although in pure terms
this is not *that* likely to happen --
I won't usually ask for the unit vector without having an actual
vector to perform that operation on).

Thanks for writing.
Zerex71 - 23 Feb 2007 14:43 GMT
> Lew wrote:
> >> Don't have instance variables for x, y and z. Define the methods in terms of
[quoted text clipped - 18 lines]
> never reference an actual instance variable "x" within the black box. They
> only need to present to API clients the view of "x" as an attribute.

So I'll ask a silly question - if I have an attribute (double x),
would it be permissible
to have x(double) as the setter and x() as the getter?

> Don't use static members unless you really intend the value to be what it is
> for the entire class. If your analytical model says, "I can have two Vectors,
> call them 'va' and 'vb', and they can contain separate values, and not be
> equal in value to each other", then the model requires that the "values" for
> Vectors be instance-level.

In my case, nothing will be constant about *all* instances of Vector.
They will
all potentially have varying x,y,z values.  So, put that way, perhaps
I need not
have member variables in a static class....I don't want to do this,
but maybe I need
a Vector class (non-static) and a VectorOps class (static).
Patricia Shanahan - 23 Feb 2007 15:54 GMT
...
> So I'll ask a silly question - if I have an attribute (double x),
> would it be permissible
> to have x(double) as the setter and x() as the getter?

Technically, it would work because the two methods have different
signatures.

From a human factors point of view, I don't think it is really desirable
to have two methods in the same class with the same name that do very
different things. Usually, a method with the same name as another, but
omitting a parameter, is a convenience method that does the same job
with a default value for the parameter.

Patricia
Zerex71 - 23 Feb 2007 16:17 GMT
> ...
>
[quoted text clipped - 12 lines]
>
> Patricia

But it is permissible, right?  That is method overloading, if I recall
correctly.
I think with a trivial member variable like x, having getX() and
setX(double) seem to
be overkill, although I am not opposed to it.

Mike
Patricia Shanahan - 23 Feb 2007 16:35 GMT
>> ...
>>
[quoted text clipped - 17 lines]
> setX(double) seem to
> be overkill, although I am not opposed to it.

Depends what you mean by "permissible". I would not do it, because I set
a higher value on the principle of minimum surprise than on terseness
when designing class interfaces.

Also, thinking in terms of "a trivial member variable" is a mistake.

There is some attribute that objects of your class all have. You have
decided it is appropriate for users of the class to be able to get and
set it. That is a matter of interface design, so changing it can affect
any code that uses the class.

You have also decided, at least for now, that the attribute is best
implemented by keeping its current value in a member variable. That is
just a matter of implementation of this class, and could be changed
without any change in the interface.

Patricia
Chris Uppal - 23 Feb 2007 16:45 GMT
> So I'll ask a silly question - if I have an attribute (double x),
> would it be permissible
> to have x(double) as the setter and x() as the getter?

Yes, it's perfectly permissible, and even rather sensible (in this case).

I should warn you that it does break a fairly widely-used convention for Java,
where methods tend to come in getX()/setX(int) pairs.  But it is only a
convention, and not (IMO) a particularly good one.

   -- chris
Zerex71 - 23 Feb 2007 20:30 GMT
On Feb 23, 11:45 am, "Chris Uppal" <chris.up...@metagnostic.REMOVE-
THIS.org> wrote:
> > So I'll ask a silly question - if I have an attribute (double x),
> > would it be permissible
[quoted text clipped - 7 lines]
>
>     -- chris

Hi Chris,

I think part of the reason I bring this up is that when all I want to
do is set a particular value for my class (Vector, for example, but
this could apply to other classes), all I really want to do is:

MyVector.x = ...
MyVector.y = ...
MyVector.z = ...

But we're supposed to be all "OO" and everything so I'm supposed to
hide my data, right?  So I have to use the overhead of
MyVector.setX(...) etc. which I think is just overkill.  Plus, I agree
with the tenets of "gOOd design" but in all reality, it's not like
thousands of people are going to be using my class and strewing the
Java landscape with my class.  It's one class in one application.  If
I can design it to be airtight for my purposes, I think that's just
fine.

One big thing that I have discovered in my coding is that most of the
time it almost doesn't matter how I implement the class, the ultimate
thing that drives my design is the elegance, look, and soundness of
the code *when it is actually invoked*.  In other words, if I do the
bottom-up thing, all's well and good until the first time I try to use
what I've coded and then I go, "Uh-oh, that doesn't look too great" so
I go back and restructure things.

Mike
Martin Gregorie - 24 Feb 2007 15:25 GMT
> One big thing that I have discovered in my coding is that most of the
> time it almost doesn't matter how I implement the class, the ultimate
[quoted text clipped - 3 lines]
> what I've coded and then I go, "Uh-oh, that doesn't look too great" so
> I go back and restructure things.

This is a good reason for not using bottom up design. IMO top-down
design combined with incremental development is the way to go. This way
you can introduce a new class with sensible (and sensibly named)
methods, test run it as a skeleton that does little more than return
values needed to check the operation of its caller and only then, when
the logic is right, do you need to write functionality into the new class.

I really hate seeing undocumented classes (there are some in the
standard class library and more in Javamail and 3rd party packages). As
skeletal descriptions are better than none I think the outline Javadoc
descriptions are best written as part of the class skeleton and then
fleshed out as code is added to the methods.

Signature

martin@   | Martin Gregorie
gregorie. | Essex, UK
org       |

angrybaldguy@gmail.com - 25 Feb 2007 07:29 GMT
> On Feb 23, 11:45 am, "Chris Uppal" <chris.up...@metagnostic.REMOVE-
>
[quoted text clipped - 4 lines]
>
> > Yes, it's perfectly permissible, and even rather sensible (in this case).

Just to clarify Chris's response a bit:

You can safely give accessors and mutators (or any other methods) the
same name provided they have different signatures (name + arguments,
basically).  That said, the getFoo/setFoo convention is VERY strongly
embedded in the Java programming culture.  It's important to obey
local conventions for the simple reason that if you ever need help
with your code, you'll spend less time explaining what getX() is doing
than what x() is doing.  That said...

> I think part of the reason I bring this up is that when all I want to
> do is set a particular value for my class (Vector, for example, but
[quoted text clipped - 6 lines]
> But we're supposed to be all "OO" and everything so I'm supposed to
> hide my data, right?

Yes, but accessors and mutators have very little to do with data
hiding.

- WARNING - WARNING - WARNING -
The following viewpoint is extremist and not completely practical on
all projects.  Take with a grain of salt as large as needed.
- WARNING - WARNING - WARNING -

"OO" doesn't mean "I have accessors and mutators for all my member
variables".  It means the code is structured around the behaviour of
each object as a whole rather than treating objects as glorified
structs.  Think about *why* you want to change just one attribute of
your mathematical Vector.  In fact, think carefully about why you want
to change the Vector at all.

I'm strongly opposed to mutable "value" objects; they complicate
making assertions about the thing the object represents
signifigantly.  Imagine for a moment if String were mutable -- every
time you passed a String into or received a String from a method
outside your control, the contents of the String might change without
the identity of the String changing.  Conversely, you'd be able to
violate "invariants" of other classes by giving them a String in a
valid state and then changing it to be an invalid state:

HashMap<String, T> stringMap = ....;
String keyA = "key a";
String keyB = "key b";

stringMap.put (keyA, valueA);
stringMap.put (keyB, valueB);

keyB.setChar(4, 'a');

And there's nothing HashMap could do to "defend" itself from this
without adding a large amount of Observer-pattern cruft to String and
complicating the class, or without copying the key Strings and using
copies instead of the original string, consuming much more memory.

To get back to Vectors and operations on them, consider working with
entire vectors at once rather than vector components.  Component
operations should be encapsulated inside the Vector objects (as
instance methods) or inside the Vector class (as static methods).  The
"x", "y", and "z" components may be exposed through accessors safely,
but not mutated outside the class.

Then if you need to represent a new mathematical vector, you represent
it with a new Vector instance either created with "new" or created by
operations on existing Vector instances, similar to how String's
"manipulation" methods like replace return new Strings.  If you no
longer need the original Vector, dispose of it and let the GC deal
with it.  If you're reasonably smart about how you use Vector objects,
you can avoid creating excess objects by keeping computed Vectors
around until you're sure you don't need them any more, which should
alleviate most "heap churn" concerns.
Chris Uppal - 25 Feb 2007 19:20 GMT
> One big thing that I have discovered in my coding is that most of the
> time it almost doesn't matter how I implement the class, the ultimate
> thing that drives my design is the elegance, look, and soundness of
> the code *when it is actually invoked*.

I know what you mean, and I too have had the sad experience of designing
something which made perfect sense on its own terms but where turned out that I
hadn't given enough thought given to its "user-interface".

But I think you may be overdoing it a little.  The superficial appearance of
the code is comparatively unimportant (within limits) -- less important than
semantic coherence anyway.  If you have to sacrifice one to get the other (and
you /will/ have to, if you are programming in Java) then prefer clean,
manageable, and complete semantics every time.

If (once you've got the semantics right) you can tweak a few things, or
introduce a few helpers and short-cut methods, to make the client code
prettier, then that's fine.  No reason not to go for it.  But don't make the
mistake on not providing a coherent, complete, "ordinary", API for places where
you don't want to prettify the user code.

Sauce on top of pasta, not sauce /instead/ of pasta...

   -- chris
John W. Kennedy - 23 Feb 2007 23:21 GMT
>> So I'll ask a silly question - if I have an attribute (double x),
>> would it be permissible
[quoted text clipped - 5 lines]
> where methods tend to come in getX()/setX(int) pairs.  But it is only a
> convention, and not (IMO) a particularly good one.

It's even a little bit more than a convention, in that Eclipse (I know)
and NetBeans (I suppose) will automatically generate them for you, and
in that they are mandatory in the JavaBeans architecture.

Signature

John W. Kennedy
"The blind rulers of Logres
Nourished the land on a fallacy of rational virtue."
  -- Charles Williams.  "Taliessin through Logres: Prelude"

Chris Uppal - 23 Feb 2007 16:51 GMT
>.I don't want to do this, but maybe I need
> a Vector class (non-static) and a VectorOps class (static).

There is no need for that, since static members are separate from instance
members anyway.  But if it helps you keep the separation clear in your head
while you are learning how to use "static" effectively, then it might be a good
idea to try for a while.

   -- chris
Alex Hunsley - 15 Feb 2007 01:11 GMT
>>  Hashtable values = new Hashtable();
>>  values.put("a", new Quaternion(1, 2, 3, 4.6));
[quoted text clipped - 3 lines]
> For my edification, why did you choose Hashtable over other Map
> implementations?

There wasn't a lot of thought put into the particular choice of which
map I used in the example! There may be more suitable choices. I did
start thinking about it when I wrote the post but realised I was
dallying too much when I had work to do, so put that particular reading
on hold and just sent my post.
lex

> - Lew


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.