Computer Science Canada

Design Patterns

Author:  Martin [ Sun Mar 06, 2005 8:49 pm ]
Post subject:  Design Patterns

An interesting read on writing better code.

Design patterns are recurring solutions to software design problems you find again and again in real-world application development. Design patterns are about design and interaction of objects, as well as providing a communication platform concerning elegant, reusable solutions to commonly encountered programming challenges.

http://www.dofactory.com/Patterns/Patterns.aspx

The sample code is in C#. It should be fairly easy to read and translate over to other languages though.

Author:  wtd [ Sun Mar 06, 2005 10:53 pm ]
Post subject: 

Honestly, I looked at these, and most of them are only really useful if you're using a completely brain-dead language like C# or Java. Sometimes you can't avoid that, but I just want to put this into perspective.

Author:  rizzix [ Sun Mar 06, 2005 11:23 pm ]
Post subject: 

wtd: whats with the unnecessary adjectives? Laughing

so anyways the stuff listed up there are really just conventions. the most important of the lot include: Factories, Iterators, Observers and Delegation (dunno but did they include that there? *shurgs*). The rest are unnecessary stuff IMHO.

Author:  wtd [ Mon Mar 07, 2005 4:33 am ]
Post subject: 

rizzix wrote:
wtd: whats with the unnecessary adjectives? Laughing


If you're counting "completely brain-dead" as unnecessary adjectives, then in the case of the languages named (and a good many others), they're quite necessary. Aside from their large libraries, and the backing of large corporations which have used their influence to quash alternatives (or at least relegate alternatives to academic curiosities), such languages have no redeeming qualities.

Now, that said, that corporate support sometimes makes them useful. However, useful does not by any means necessarily mean good, and any computer scientist should know the difference.

Author:  Martin [ Mon Mar 07, 2005 8:54 am ]
Post subject: 

One of the uses of design patters is that (apparently) they help to write platform independant code.

I have a course on them in my 2A semester (Jan - Apr 2006).

Author:  rizzix [ Mon Mar 07, 2005 3:06 pm ]
Post subject: 

wtd wrote:
rizzix wrote:
wtd: whats with the unnecessary adjectives? Laughing


If you're counting "completely brain-dead" as unnecessary adjectives, then in the case of the languages named (and a good many others), they're quite necessary. Aside from their large libraries, and the backing of large corporations which have used their influence to quash alternatives (or at least relegate alternatives to academic curiosities), such languages have no redeeming qualities.
welll. thats your opinion...

Author:  wtd [ Mon Mar 07, 2005 3:27 pm ]
Post subject: 

Name a single good thing either language contains which is not merely intended to compensate for some other basic deficiency.

Author:  Martin [ Mon Mar 07, 2005 4:04 pm ]
Post subject: 

C# is backed by the most profitable company ever.

Wait a second...

Author:  Tony [ Mon Mar 07, 2005 4:24 pm ]
Post subject: 

University of Waterloo was paid $12mil to start teaching C#.

Wait a second...

Author:  wtd [ Mon Mar 07, 2005 5:35 pm ]
Post subject: 

Heh. I already mentioned backing by large corporations. Smile

And if we're going to count that, Java's on a pretty solid footing. IBM, Sun, HP, etc. all throwing their weight behind it.

Author:  Hikaru79 [ Mon Mar 07, 2005 8:28 pm ]
Post subject: 

If we're going to go with that method of argument, name some things that these languages LACK that others don't Wink

Author:  wtd [ Mon Mar 07, 2005 9:17 pm ]
Post subject: 

  • Decent support for generics. Not only based on type. Consider templates in C++ or generics in Ada. A simple example: a lottery ticket.

    code:
    template <size_t N>
    class LotteryTicket
    {
       private:
          int numbers[N];
       public:
          LotteryTicket();
          int operator[](size_t index) const;
          bool operator==(const LotteryTicket<N>& other_ticket) const;
          int matching_numbers(const LotteryTicket<N>& other_ticket) const;
    };


    code:
    generic
       N : Positive;
    package Lottery_Ticket is
       subtype Index_Type is Positive range 1..N;
       type Ticket is limited private;
       
       procedure Make(T : out Ticket);
       function "()" (T : in Ticket; Index : in Index_Type) return Integer;
       function "=" (T1, T2 : in Ticket) return Boolean;
       function Matching_Numbers(T1, T2 : in Ticket) return Natural;
    private
       type Ticket is array (1..N) of Integer;
    end Lottery_Ticket;

  • The ability to deal with functions as first class entities. Let's say I have a Name class with first and last name properties.

    code:
    using System;

    class Name
    {
       private string first, last;

       public this(string f, string l)
       {
          first = f;
          last = l;
       }

       public string First
       {
          get { return first; }
       }

       public string Last
       {
          get { return last; }
       }
    }


    Now, how do I sort based on last name? Why shouldn't it be as simple as:

    code:
    class Name
       attr_reader :first, :last

       def initialize(first, last)
          @first, @last = first, last
       end
    end

    names = [Name.new("Bob", "Smith"), Name.new("John", "Doe")]
    sorted_names = names.sort { |a, b| a.last <=> b.last }


    Or:

    code:
    data Name = Name {first::String, last::String}

    names = [Name "Bob" "Smith", Name "John" "Doe"]
    sortedNames = sortBy (\a b -> last a `compare` last b) names

  • Why should it be difficult to construct lists? Neither Java nor C# offer sane syntax for expediting the creation of many useful data structures (lists, vectors, hashtables).
  • No standalone functions. Heck, Java and C# even acknowledge the need for such by including static members and member functions. Yet, somehow these got left out.
  • Multiple inheritance. MI can greatly reduce the need for standalone functions and data, but it's missing too. Consider the case of Eiffel vs. Java, for instance. In Java you use System.out, which is static member of the System class. In Eiffel, all classes inherit std_output, so they can use such things without having to go into a different class.


Let's see the reaction to those before I go on. Smile

Author:  rizzix [ Mon Mar 07, 2005 9:58 pm ]
Post subject: 

Ha! Its all missleading. You see you've just pointed out mostly to syntax sugar that Java and C# dont have. The idea behind Java and C#, is to include the bare minimum in the language and knock out the additional stuff into libraries. This i believe is a plus point on behalf of Java and C#, most other languages are simply bloated, but these two languages have rich and diverse libraries.

- templates
well ur temaplate design is bad. its is not a good idea to pass values as arguments to templates since you'll almost never come across the "need" to do so (unnecessary syntax sugar leads to a TIMTOWTDI effect, which is bad as far as full-fledge programming languages are concerned. scripting languages are an exception). As for types, java has generics, and java does it far better than c++, taking care of the potential flaws with the c++ template design. The only downfall (due to generics in java) is the fact that learning java just got a little harder, with the added complexity. (but java was never intended to be the easiest language to learn)

- functions as first class entities
As i said syntax sugar. It does reduce code but is not required. In java the same thing can be accomplished likewise:
code:
public class Name {
   private String first, last;

   public Name(String f, String l)
   {
      first = f;
      last = l;
   }

   public String getFirst {return first;}
   public String getLast {return last;}
}
code:
import java.util.*; ...

Name[] names = {new Name("Bob", "Smith"), new Name("John", "Doe")};

Arrays.sort(names,
    new Comparator() {
        public int compare(Name n1, Name n2) {
            return n1.getLast().compareTo(n2.getLast());
        }
    }
);


- Construction of lists
It would be a good idea to have syntax sugar for hashtables at the least, in Java or C#. But its difficult to change that now.

- No standalone functions
That would go against the consistancy and idealogy of both these languages. These languages depict object interactions, with only one class of the many, being the application class (has the "main" method). I dont see this as a drawback but rather as a plus point. The language is not bloated with features and syntax sugar.

- Multiple inheritance
What happens when two classes define the same symbols? But it is a fact that Single Inheritance has lead to less complexity in object design and modelling (specially in 1000000 lins of code projects) thus further supports extensibility and maintainance once again specially in large projects (hence the awesome support by huge firms). The only drawback is that designing is more difficult as compared to MI design. If ur not a big fan of design before code, then you might as well stay away from these langauges.

Author:  Hikaru79 [ Mon Mar 07, 2005 10:02 pm ]
Post subject: 

Razz Wow. WTD never disappoints! ^__^

I just have a few questions. I'm only just starting C++ so I don't understand what you mean by "templates" but just by looking at it, it looks an awful lot like an interface or abstract class in java. I'm guessing there's a vital difference there... what is it?

Also, Java *does* have Vectors and the other stuff you mention... or did you just mean you don't like the way that they're implemented?

Author:  rizzix [ Mon Mar 07, 2005 10:09 pm ]
Post subject: 

wait sorry, my gernerics counter might not have properly countered ur argument: i dont know ada.

Author:  wtd [ Mon Mar 07, 2005 10:26 pm ]
Post subject: 

rizzix wrote:
Ha! Its all missleading. You see you've just pointed out mostly to syntax sugar that Java and C# dont have. The idea behind Java and C#, is to include the bare minimum in the language and knock out the additional stuff into libraries. This i believe is a plus point on behalf of Java and C#, most other languages are simply bloated, but these two languages have rich and diverse libraries.


Bloated? Really. Have you studied languages like Ruby, Haskell, Eiffel? Their syntaxes are anything but bloated.

rizzix wrote:
- templates
well ur temaplate design is bad. its is not a good idea to pass values as arguments to templates since you'll almost never come across the "need" to do so. As for types, java has generics, and java does it far better than c++, taking care of the potential flaws with the c++ template design. The only downfall (due to generics in java) is the fact that learning java just got a little harder, due to the added complexity. (but java was never intended to be the easiest language to learn)


How is my use of templates flawed? All I've done is provide a compile-time (vs. run-time) assurance that we'll never have something like a 7 number lottery ticket being compared to a 6 number lottery ticket.

Having checks at compile-time is generally preferable to run-time checks where possible. Of course, I'm also a fan of languages which do most checking at run-time, like Ruby, but in those cases there're typically other benefits.

What are the potential flaws with the C++ template system you refer to, if I may ask?

rizzix wrote:
- functions as first class entities
As i said syntax sugar. It does reduce code but is not required. In java the same thing can be accomplished likewise:
code:
public class Name {
   private String first, last;

   public Name(String f, String l)
   {
      first = f;
      last = l;
   }

   public String getFirst {return first;}
   public String getLast {return last;}
}
code:
import java.util.*; ...

Name[] names = {new Name("Bob", "Smith"), new Name("John", "Doe")};

Arrays.sort(names,
    new Comparator() {
        public int compare(Name n1, Name n2) {
            return n1.getLast().compareTo(n2.getLast());
        }
    }
);


Yes, there's that, but that isn't really functions as first class entities, and yes it does go deeper than syntacic sugar, though that should be enough motivation. Making good methods syntactically easy encourages their use.

[quote="rizzix"]- Construction of lists
It would be a good idea to have syntax sugar for hashtables at the least, in Java or C#. But its difficult to change that now.

Why? Look at Groovy for an example of this working just peachy with Java.

rizzix wrote:
- No standalone functions
That would go against the consistancy and idealogy of both these languages. These languages depict object interactions, with only one class of the many, being the application class (has the "main" method). I dont see this as a drawback but rather as a plus point. The language is not bloated.


Ok, let's look at how Ruby manages this. Everything that goes into what seems like the global space gets added to the Object class. Since every class inherits from Object, other classes can use that method.

code:
def foo
   "foo"
end

class Bar
   def initialize
      puts foo
   end
end


It looks like the Bar class is simply using the global foo method. Instead it looks like this to the compiler:

code:
class Object
   def foo
      "foo"
   end
end

class Bar < Object
   def initialize
      puts foo
   end
end


rizzix wrote:
- Multiple inheritance
What happens when two classes define the same symbols? But it is a fact that Single Inheritance has lead to less complexity in object design and modelling (specially in 1000000 lins of code projects) thus further supports extensibility and maintainance once again specially in large projects (hence the awesome support by huge firms). The only drawback is that designing is more difficult as compared to MI design. If ur not a big fan of design before code, then you might as well stay away from these langauges.


Single inheritance is easier, but MI is not by any means impossible. It certainly gets used in C++, Eiffel, and Perl with little trouble. When name errors do arise these languages have mechanisms for removing ambiguity.

And it's quite useful for modelling some problems. Let's say I want a class which represents a student. Clearly handling the student's name and their grades are entirely separate problems, so they should be modelled that way.

code:
#include <string>
#include <vector>

class Name
{
        private:
                const std::string _first, _last;
        public:
                Name(std::string f, std::string l): _first(f), _last(l) { }
               
                std::string first() const
                {
                        return _first;
                }
               
                std::string last() const
                {
                        return _last;
                }
};

class GradesCollection : public std::vector<int>
{
        public:
                GradesCollection() : std::vector<int>() { }

                int sum_grades() const
                {
                        int sum = 0;
                        for (const_iterator i(begin()); i != end(); ++i)
                                sum += *i;
                        return sum;
                }
               
                double average_grade() const
                {
                        return sum_grades() / size();
                }
};

class Student : public Name, public GradesCollection
{
        public:
                Student(std::string f, std::string l)
                : Name(f, l)
                , GradesCollection()
                { }
};

Author:  wtd [ Mon Mar 07, 2005 10:35 pm ]
Post subject: 

Hikaru79 wrote:
Razz Wow. WTD never disappoints! ^__^

I just have a few questions. I'm only just starting C++ so I don't understand what you mean by "templates" but just by looking at it, it looks an awful lot like an interface or abstract class in java. I'm guessing there's a vital difference there... what is it?


A template is a compile-time mechanism. It doesn't produce executable code, (which is why they go in .h files), but rather a "template" for executable code.

When I declare:

code:
template <size_t N> LotteryTicket


I simply provide a "template" for LotteryTicket classes. When I later use:

code:
LotteryTicket<7>


The compiler creates a class for me where N is replaced by 7. Think of it like macros... only safer, and much more powerful.

Hikaru79 wrote:
Also, Java *does* have Vectors and the other stuff you mention... or did you just mean you don't like the way that they're implemented?


Exactly. It's inconvenient to use them, so a lot of people don't, and that leads to problems. Lots of problems.

Author:  rizzix [ Mon Mar 07, 2005 11:35 pm ]
Post subject: 

wtd wrote:
Bloated? Really. Have you studied languages like Ruby, Haskell, Eiffel? Their syntaxes are anything but bloated.
No, but the fact that I can do everything those languages can do with the limited syntax of Java and C# does make it seem as though those languages are simply bloated.

wtd wrote:
How is my use of templates flawed? All I've done is provide a compile-time (vs. run-time) assurance that we'll never have something like a 7 number lottery ticket being compared to a 6 number lottery ticket.
Yes good argument, it is also preferable to move as far as possible, the error checking to compiler time even in the Java world (hence generics). But that is really not the real reason to the use of value passing in that example. The real reason is that C arrays do not hold length information, hence you are forced to rely on templates to take care of this drawback in C. And templates is simple the only better way to work around this,, originally C programmers would use macros, but macors dont result in compiler errors.

wtd wrote:
What are the potential flaws with the C++ template system you refer to, if I may ask?
The folling link will explain it all (it's kinda complex) and will detail the reasons as to why the modifications were made: http://java.sun.com/docs/books/tutorial/extra/generics/


wtd wrote:
Yes, there's that, but that isn't really functions as first class entities, and yes it does go deeper than syntacic sugar, though that should be enough motivation. Making good methods syntactically easy encourages their use.
Not to mention the Comparator object could be refered to by a reference and reused in various other Arrays.sort calls for various other arrays.

wtd wrote:
Why? Look at Groovy for an example of this working just peachy with Java.
Groovy does use the Java platform but it is a whole new language. For java to implement this syantax requires the Java Language Specification to be ameded, which is a long process and quite a pain in the neck. Either way i must mention the use of HashTables result in a heavy use of RAM memory. HashTables work on the basis that strings can be represented as a number of a fixed length (like int, short etc). This process is known as hashing. Hash functions vary in that they provide for a disctinct number on either a small range or large range of values (the domain). The larger the domain the more varied a string can be hashed. But behind the scenes all these hashed values are used as the index of a generic array. Thus the array has to be large enough to cover the entire domain of the hash function. Hence the increase in memory use.

wtd wrote:
Ok, let's look at how Ruby manages this. Everything that goes into what seems like the global space gets added to the Object class. Since every class inherits from Object, other classes can use that method.

code:
def foo
   "foo"
end

class Bar
   def initialize
      puts foo
   end
end


It looks like the Bar class is simply using the global foo method. Instead it looks like this to the compiler:

code:
class Object
   def foo
      "foo"
   end
end

class Bar < Object
   def initialize
      puts foo
   end
end
No argument.



wtd wrote:
Single inheritance is easier, but MI is not by any means impossible. It certainly gets used in C++, Eiffel, and Perl with little trouble. When name errors do arise these languages have mechanisms for removing ambiguity.

And it's quite useful for modelling some problems. Let's say I want a class which represents a student. Clearly handling the student's name and their grades are entirely separate problems, so they should be modelled that way.

code:
#include <string>
#include <vector>

class Name
{
        private:
                const std::string _first, _last;
        public:
                Name(std::string f, std::string l): _first(f), _last(l) { }
               
                std::string first() const
                {
                        return _first;
                }
               
                std::string last() const
                {
                        return _last;
                }
};

class GradesCollection : public std::vector<int>
{
        public:
                GradesCollection() : std::vector<int>() { }

                int sum_grades() const
                {
                        int sum = 0;
                        for (const_iterator i(begin()); i != end(); ++i)
                                sum += *i;
                        return sum;
                }
               
                double average_grade() const
                {
                        return sum_grades() / size();
                }
};

class Student : public Name, public GradesCollection
{
        public:
                Student(std::string f, std::string l)
                : Name(f, l)
                , GradesCollection()
                { }
};
The biggest drawback in MI is the overhead complexity that should be excluded in any project specially those with complex heirarichal structures. Following conventions does not guarantee anything. It is very likely the feature available will be abused in some way or another. Either way in ur example it is best that the Name of the student is used as a property of the Student class, your OOD is flawed.

wrote:

Hikaru79 wrote:
Also, Java *does* have Vectors and the other stuff you mention... or did you just mean you don't like the way that they're implemented?


Exactly. It's inconvenient to use them, so a lot of people don't, and that leads to problems. Lots of problems.
Thats a lie. Infact IMO its the other way around. The Java's Vector class is one of the most used classes in any java application. The entire java standard library by far is quite superior that that of the stl. Not to mention the documentation avaialable for the java API as compared to that for the stl, java's outbeats it anyday. Name something that the the stl library can do better than that of Java's.

Author:  wtd [ Tue Mar 08, 2005 7:15 pm ]
Post subject: 

rizzix wrote:
wtd wrote:
Bloated? Really. Have you studied languages like Ruby, Haskell, Eiffel? Their syntaxes are anything but bloated.
No, but the fact that I can do everything those languages can do with the limited syntax of Java and C# does make it seem as though those languages are simply bloated.


Let me assure you, while some are (there are lots of languages and speaking in absolutes is the path to madness), the languages I've mentioned aren't. They simply provide good syntax and library level support for common data structures and what you might call "design patterns." Notably things like pre and post condition checks.

Generally the inclusion of such things leads to much more elegant, less bloated code since a single standard (and typically sane) means of accomplishing a task is provided. Programmers need not find their own ways to solve simple problems (though doing so is not necessarily bad from a learning experience point of view).

Consider the task of taking one array/list and mutating each element, then saving the result in another array/list.

Java 5.0:
code:
int[] foo = new int[10];
int[] bar = new int[10];

for (int i = 0; i < 10; i++)
   foo[i] = i;

for (int i = 0; i < 10; i++)
   bar[i] = foo[i] * 2;


Haskell:
code:
foo = [0..9]
bar = map (* 2) foo


Why shouldn't it be that easy? Haskell has a simpler syntax, after all.

rizzix wrote:
wtd wrote:
How is my use of templates flawed? All I've done is provide a compile-time (vs. run-time) assurance that we'll never have something like a 7 number lottery ticket being compared to a 6 number lottery ticket.


Yes good argument, it is also preferable to move as far as possible, the error checking to compiler time even in the Java world (hence generics). But that is really not the real reason to the use of value passing in that example. The real reason is that C arrays do not hold length information, hence you are forced to rely on templates to take care of this drawback in C. And templates is simple the only better way to work around this,, originally C programmers would use macros, but macors dont result in compiler errors.


The reasoning behind C++ templates is not what you think it is. I could easily create a class which emulates an array, stores size, and only stores a single kind of value.

code:
#include <stdlib.h>

class MyVector
{
   private:
      int *_data;
      size_t _size;
   public:
      MyVector() : _data(new int[0]), _size(0) { }
      MyVector(size_t size) : _data(new int[size]), _size(size) { }
      ~MyVector() { delete [] _data; _size = 0; }
      /* yada yada */
};


What the template system gives me is type safety. Yes, Java has generics, but they're really half-assed. I'll grant you that they're an improvement, but they still leave a lot to be desired. Out of concern for backwards compatibility (which they later broke anyway) Sun didn't give the Java community real generics. Instead, what you get is truly syntactic sugar for casts which are still there and still can be troublesome. The C++ solution eliminates casts.

rizzix wrote:
wtd wrote:
What are the potential flaws with the C++ template system you refer to, if I may ask?
The folling link will explain it all (it's kinda complex) and will detail the reasons as to why the modifications were made: http://java.sun.com/docs/books/tutorial/extra/generics/


I'm actually familiar with generics in Java. Compared to C++, Ada and Eiffel (not to mention Haskell and O'Caml), they're not impressive.

rizzix wrote:
wtd wrote:
Yes, there's that, but that isn't really functions as first class entities, and yes it does go deeper than syntacic sugar, though that should be enough motivation. Making good methods syntactically easy encourages their use.
Not to mention the Comparator object could be refered to by a reference and reused in various other Arrays.sort calls for various other arrays.


Ok, here's the same idea.

code:
data Name = Name {first::String, last::String}

names = [Name "Bob" "Smith", Name "John" "Doe"]
sortedNames = sortBy (\a b -> last a `compare` last b) names


Now, if I want my "comparator" function as a function I can use elsewhere:

code:
compareNames a b = last a `compare` last b


Or better yet:

code:
compareNames (Name _ a) (Name _ b) = a `compare` b


Then the sorting looks like:

sortedNames = sortBy compareNames names[/code]

And for comparing lots of lists of names:

code:
sortNames = sortBy compareNames


Then:

code:
sortedNames = sortNames names


Can you achieve something sort of similar in Java if you try? Yes. Why should it be hard, though?

rizzix wrote:
wtd wrote:
Why? Look at Groovy for an example of this working just peachy with Java.
Groovy does use the Java platform but it is a whole new language. For java to implement this syantax requires the Java Language Specification to be ameded, which is a long process and quite a pain in the neck. Either way i must mention the use of HashTables result in a heavy use of RAM memory. HashTables work on the basis that strings can be represented as a number of a fixed length (like int, short etc). This process is known as hashing. Hash functions vary in that they provide for a disctinct number on either a small range or large range of values (the domain). The larger the domain the more varied a string can be hashed. But behind the scenes all these hashed values are used as the index of a generic array. Thus the array has to be large enough to cover the entire domain of the hash function. Hence the increase in memory use.


Hashtables need not be that memory-intensive, though the trade-off can be increased CPU usage. The general truth is that you can either code fast, or run fast. Trying to optimize every little thing is not terribly easy.

The truth is, hashtables are often immensely useful.

[quote="rizzix"]
wtd wrote:
Ok, let's look at how Ruby manages this. Everything that goes into what seems like the global space gets added to the Object class. Since every class inherits from Object, other classes can use that method.

code:
def foo
   "foo"
end

class Bar
   def initialize
      puts foo
   end
end


It looks like the Bar class is simply using the global foo method. Instead it looks like this to the compiler:

code:
class Object
   def foo
      "foo"
   end
end

class Bar < Object
   def initialize
      puts foo
   end
end
No argument.



rizzix wrote:
wtd wrote:
Single inheritance is easier, but MI is not by any means impossible. It certainly gets used in C++, Eiffel, and Perl with little trouble. When name errors do arise these languages have mechanisms for removing ambiguity.

And it's quite useful for modelling some problems. Let's say I want a class which represents a student. Clearly handling the student's name and their grades are entirely separate problems, so they should be modelled that way.

code:
#include <string>
#include <vector>

class Name
{
        private:
                const std::string _first, _last;
        public:
                Name(std::string f, std::string l): _first(f), _last(l) { }
               
                std::string first() const
                {
                        return _first;
                }
               
                std::string last() const
                {
                        return _last;
                }
};

class GradesCollection : public std::vector<int>
{
        public:
                GradesCollection() : std::vector<int>() { }

                int sum_grades() const
                {
                        int sum = 0;
                        for (const_iterator i(begin()); i != end(); ++i)
                                sum += *i;
                        return sum;
                }
               
                double average_grade() const
                {
                        return sum_grades() / size();
                }
};

class Student : public Name, public GradesCollection
{
        public:
                Student(std::string f, std::string l)
                : Name(f, l)
                , GradesCollection()
                { }
};
The biggest drawback in MI is the overhead complexity that should be excluded in any project specially those with complex heirarichal structures. Following conventions does not guarantee anything. It is very likely the feature available will be abused in some way or another. Either way in ur example it is best that the Name of the student is used as a property of the Student class, your OOD is flawed.


So, because a feature which is potentially incredibly useful may be abused, it should be removed from the language entirely? Read Bertrand Meyer's Object-Oriented Software Construction. Multiple inheritance can be done right, and when it is, it's a very good thing for code re-use.

rizzix wrote:
wtd wrote:

Hikaru79 wrote:
Also, Java *does* have Vectors and the other stuff you mention... or did you just mean you don't like the way that they're implemented?


Exactly. It's inconvenient to use them, so a lot of people don't, and that leads to problems. Lots of problems.
Thats a lie. Infact IMO its the other way around. The Java's Vector class is one of the most used classes in any java application. The entire java standard library by far is quite superior that that of the stl. Not to mention the documentation avaialable for the java API as compared to that for the stl, java's outbeats it anyday. Name something that the the stl library can do better than that of Java's.


Show me a function which will swap any two variables of type T where T is any type. Show me how I'd sort just the first ten items in a vector, list, array, etc.

Author:  rizzix [ Wed Mar 09, 2005 4:07 pm ]
Post subject: 

wtd wrote:
Java 5.0:
code:
int[] foo = new int[10];
int[] bar = new int[10];

for (int i = 0; i < 10; i++)
   foo[i] = i;

for (int i = 0; i < 10; i++)
   bar[i] = foo[i] * 2;


Haskell:
code:
foo = [0..9]
bar = map (* 2) foo


Why shouldn't it be that easy? Haskell has a simpler syntax, after all.
No Argument.


wtd wrote:
Yes, Java has generics, but they're really half-assed. I'll grant you that they're an improvement, but they still leave a lot to be desired. Out of concern for backwards compatibility (which they later broke anyway) Sun didn't give the Java community real generics. Instead, what you get is truly syntactic sugar for casts which are still there and still can be troublesome. The C++ solution eliminates casts.
wtd wrote:
I'm actually familiar with generics in Java. Compared to C++, Ada and Eiffel (not to mention Haskell and O'Caml), they're not impressive.
What more do you need besides type-safety, considering that Java is much more dynamic than C++. And elaborate on "half-assed", show me how, and what you mean, exculding examples that include the passing of 'values', since we have established Java does not have that (and as I commented, its unnecessay).


wtd wrote:
...Can you achieve something sort of similar in Java if you try? Yes. Why should it be hard, though?
Its not harder just different. But if you mean by harder that it takes a few extra lines of code.. then maybe, but its insignificant comparatively. Java's way of going about it also provides a form of encapsulation over the sorting algorithm. You sorted you object based on a rather simple criteria, but in the real-world the criteria could be much complex. In these cases I see the Java's way as the prefered method. For example the retained Comparator object can be passed to other objects where its state maybe modified. Based on its current state and other factors it would modify its sorting criteria etc. Thus this proves to be a more versatile solution.



wtd wrote:
So, because a feature which is potentially incredibly useful may be abused, it should be removed from the language entirely? Read Bertrand Meyer's Object-Oriented Software Construction. Multiple inheritance can be done right, and when it is, it's a very good thing for code re-use.
A good language should aviod abuse as far as possible, cuz just as stated in Murphy's Law: "Anything that can go wrong will go wrong". Now look at a huge firm that has 1000s of programmer under it, the probability of abuse is much higher. Also not to mention opensource projects.



wtd wrote:
Show me a function which will swap any two variables of type T where T is any type. Show me how I'd sort just the first ten items in a vector, list, array, etc.
Actually for arrays most of this is already possible. But of the rest of the Collection framework, java lacks the functions. To overcome this drawback there's the jaxlib's jax.col.* classes which cover all these little details and much more. Also: The Java Collection Framework is thread-safe, how about stl?

Author:  wtd [ Wed Mar 09, 2005 7:31 pm ]
Post subject: 

rizzix wrote:
What more do you need besides type-safety, considering that Java is much more dynamic than C++. And elaborate on "half-assed", show me how, and what you mean, exculding examples that include the passing of 'values', since we have established Java does not have that (and as I commented, its unnecessay).


code:
class Dog
{
        public Dog() { super(); }

        public void talk()
        {
                System.out.println("Woof!");
        }
}

class Robot
{
        public Robot() { super(); }

        public void talk()
        {
                System.out.println("More oil, please.");
        }
}

class Tree
{
        public Tree() { super(); }

        public void bark()
        {
                System.out.println("Rough");
        }
}

public class Test
{
        public static void main(String[] args)
        {
                speak(new Dog());
                speak(new Robot());
                speak(new Tree());
        }

        private static <T> void speak(T speaker)
        {
                speaker.talk();
        }
}


This doesn't compile. It doesn't even compile if we remove:

code:
speak(new Tree());


What's the error?

code:
Test.java:42: cannot find symbol
symbol  : method talk()
location: class java.lang.Object
                speaker.talk();
                       ^
1 error


Basically, T is being really treated like Object, so I can only call Object methods on the speaker object. To make it work, I have to write this as:

code:
interface Speaks
{
        public void talk();
}

class Dog implements Speaks
{
        public Dog() { super(); }

        public void talk()
        {
                System.out.println("Woof!");
        }
}

class Robot implements Speaks
{
        public Robot() { super(); }

        public void talk()
        {
                System.out.println("More oil, please.");
        }
}

class Tree
{
        public Tree() { super(); }

        public void bark()
        {
                System.out.println("Rough");
        }
}

public class Test
{
        public static void main(String[] args)
        {
                speak(new Dog());
                speak(new Robot());
//              speak(new Tree());
        }

        private static <T extends Speaks> void speak(T speaker)
        {
                speaker.talk();
        }
}


In which case I might as well have written:

code:
interface Speaks
{
        public void talk();
}

class Dog implements Speaks
{
        public Dog() { super(); }

        public void talk()
        {
                System.out.println("Woof!");
        }
}

class Robot implements Speaks
{
        public Robot() { super(); }

        public void talk()
        {
                System.out.println("More oil, please.");
        }
}

class Tree
{
        public Tree() { super(); }

        public void bark()
        {
                System.out.println("Rough");
        }
}

public class Test
{
        public static void main(String[] args)
        {
                speak(new Dog());
                speak(new Robot());
//              speak(new Tree());
        }

        private static void speak(Speaks speaker)
        {
                speaker.talk();
        }
}


Though the generic way does have merit (within the context of previous limitations placed on the Java language at least) when you require multiple arguments or variables to be of the same type that implements Speaks.

rizzix wrote:
wtd wrote:
...Can you achieve something sort of similar in Java if you try? Yes. Why should it be hard, though?


Its not harder just different. But if you mean by harder that it takes a few extra lines of code.. then maybe, but its insignificant comparatively. Java's way of going about it also provides a form of encapsulation over the sorting algorithm. You sorted you object based on a rather simple criteria, but in the real-world the criteria could be much complex. In these cases I see the Java's way as the prefered method. For example the retained Comparator object can be passed to other objects where its state maybe modified. Based on its current state and other factors it would modify its sorting criteria etc. Thus this proves to be a more versatile solution.


Provide me with a more complex sorting problem and we'll compare solutions. Smile

Author:  wtd [ Wed Mar 09, 2005 7:33 pm ]
Post subject: 

rizzix wrote:
A good language should aviod abuse as far as possible


Java has casts and automatic promotion (int -> float and such). They're a huge potential problem, and a nuisance at best. Is it a bad language for having them?

Author:  Naveg [ Wed Mar 09, 2005 9:36 pm ]
Post subject: 

wow, i've never seen such a true love of programming before. All i can say is that you guys are truly dedicated to what you do, and you should both be commended.

Author:  Andy [ Wed Mar 09, 2005 9:37 pm ]
Post subject: 

errr you do realize both of them have jobs in the tech field rite?

Author:  Naveg [ Wed Mar 09, 2005 11:06 pm ]
Post subject: 

yea, and its good to know we have people who care so much and know what theyre doing in those jobs.

Author:  wtd [ Wed Mar 09, 2005 11:11 pm ]
Post subject: 

Vladimir wrote:
wow, i've never seen such a true love of programming before. All i can say is that you guys are truly dedicated to what you do, and you should both be commended.


Thank you.

Author:  Martin [ Thu Mar 10, 2005 8:37 am ]
Post subject: 

Rizzix, how old are you, and where do you work?

Author:  rizzix [ Thu Mar 10, 2005 9:35 am ]
Post subject: 

I dont work, 18.

Author:  Martin [ Thu Mar 10, 2005 10:16 am ]
Post subject: 

That's what I thought. Alright, gentlemen, carry on.

Author:  rizzix [ Thu Mar 10, 2005 3:33 pm ]
Post subject: 

wtd wrote:
Java has casts and automatic promotion (int -> float and such). They're a huge potential problem, and a nuisance at best. Is it a bad language for having them?
Automatic type promotion is much better than type casting (like in c/c++). And yes casting can be abused (although its quite restrictive in java, but thats no excuse) hence 1.5 came out with generics to reduce the unnecessay (forced) casts that were required specially when using the Collection Framework. So, all in all, the java language hasn't reached it's final state yet, it is evolving and for the better. I guess we can agree its not simply a brain-dead language now, can we? Wink

As for the comparator example i'd rather not, i feel like closing this debate now, i hate arguing anyways, heh. Laughing It maybe true that those other languages u use in ur arguments can accomplish the sorting based on complex criterias but i doubt they can do it through encapsulating the entire criteria, state, etc in some form or the other... similar to java and its OO method. Unless of course you create an object just for that purpose. If thats the case, I see the java way the better way.

Author:  wtd [ Thu Mar 10, 2005 7:08 pm ]
Post subject: 

Arguing is good. It brings stuff to the surface that wouldn't otherwise get discussed. Smile

As for encapsulation, you still have to access the objects being compared from a public viewpoint. You can't have any special access to their internal state.

The only thing I can think of is adding an instance variable to your Comparator class which compare updates, but I'm not sure where that would be useful or wise. The only behavior I can see that permitting is for the comparison to change after a certain number of comparisons have been made, which could result in something really bizarre.

Of course, in any such debate confusion is likely to reign, particularly over the issue of mutable state. Of course, if you're talking about a default sorting algorithm of some complexity, I can do that with Haskell too. Smile

Let's say I create a Name data type like so, with two constructors and for which we have the ability to stringify, test for equality, and compare:

code:
data Name = Name2 {first::String, last::String} | Name3 {first::String , middle::String, last::String} deriving (Eq)

instance Show Name where
   show (Name2 f l) = f ++ " " ++ l
   show (Name3 f m l) = f ++ " " ++ m ++ " " ++ l

instance Ord Name where
   compare (Name2 f1 l1) (Name2 f2 l2) =
      case compare l1 l2 of
         EQ -> compare f1 f2
         n  -> n
   compare (Name3 f1 m1 l1) (Name3 f2 m2 l2) =
      case compare l1 l2 of
         EQ -> case compare f1 f2 of
            EQ -> compare m1 m2
            n  -> n
         n  -> n
   compare (Name2 f1 l1) (Name3 f2 _ l2) =
      case compare l1 l2 of
         EQ -> compare f1 f2
         n  -> n
   compare (Name3 f1 _ l1) (Name2 f2 l2) =
      case compare l1 l2 of
         EQ -> compare f1 f2
         n  -> n


Roughly equivalent to the following Java:

Java:
class Name implements Comparable<Name>
{
   private String first, middle, last;

   public Name(String first, String last)
   {
      this.first = first;
      this.last = last;
      this.middle = null;           
   }

   public Name(String first, String middle, String last)
   {
      this.first = first;
      this.last = last;
      this.middle = middle;           
   }

   public String getFirst() { return first; }
   public String getMiddle() { return middle; }
   public String getLast() { return last; }

   public String toString()
   {
      if (hasMiddle())
         return first + " " + middle + " " + last;
      else
         return first + " " + last;
   }

   public boolean hasMiddle() { return middle != null; }

   public boolean equals(Object o)
   {
      Name n = (Name)o;
      return (first == n.getFirst() && middle == n.getMiddle() && last == n.getLast());         
   }

   public int compareTo(Name n)
   {
      int cmp;

      // Compare names with middle names.
      // First sort on last name, then first name, then middle name
      if (this.hasMiddle() && n.hasMiddle())
      {
         switch (cmp = this.last.compareTo(n.getLast()))
         {
            case 0:
               switch (cmp = this.first.compareTo(n.getFirst()))
               {
                  case 0:
                     return this.middle.compareTo(n.getMiddle());
                  default:
                     return cmp;
               }
            default:
               return cmp;               
         }
      }
      // Compare names on a first and last name basis only
      else
      {
         switch (cmp = this.last.compareTo(n.getLast()))
         {
            case 0:
               return this.first.compareTo(n.getFirst());
            default:
               return cmp;
         }
      }
   }
}


Is it wrong that this is fun? Smile

Author:  Martin [ Thu Mar 10, 2005 7:17 pm ]
Post subject: 

A three page online debate without anybody saying 'f-a-g'

That's gotta be a first.
Nick-just-couldn't-resis editt: stop being gay, Martin

Author:  rizzix [ Thu Mar 10, 2005 7:53 pm ]
Post subject: 

wtd: yea.. and maybe adding there an ascending/decending state as well. (refering to example)

I also see the java approach seemlessly intergrating with MVC architecture: where a controller object is passed the comparator object, changing it's state based on user intereaction. At the same time (upon a risen event) the controller issues change notifications to various observers. The model also having a reference to the comparator and being one of the observers could update itself (thus a sort is in action). But the difference here is that the compartor has its state changed. Hence the sort results are different. The view is then notified and the results are displayed.

Author:  wtd [ Thu Mar 10, 2005 8:05 pm ]
Post subject: 

The problem I see with that approach (mutable comparator) is that it could cause a lot of oddities with regards to different sorting strategies (number of passes and such).

Author:  rizzix [ Thu Mar 10, 2005 8:08 pm ]
Post subject: 

Hmm, well i can;t see how that could be a problem, so long as the comparator and the sort method calls are in the same thread.

edit: but even if they arn't, in this case, i guess you would just have to block futher sort events till the view is updated.

Author:  wtd [ Thu Mar 10, 2005 8:12 pm ]
Post subject: 

rizzix wrote:
wtd: yea.. and maybe adding there an ascending/decending state as well. (refering to example)


When you have comparable data (by implementing Comparable in the Java example, and by making Name an instance of the Ord class in Haskell), you have everything there that's necessary. The sort method/function should then be able to control ascending or descending state (based on the output of compareTo/compare).

Of course, the obvious answer is that you only need to be able to sort in an ascending manner, then reverse the list/array. Smile

Author:  rizzix [ Thu Mar 10, 2005 8:15 pm ]
Post subject: 

that may be the case for the ascending/decending state. but lets take a table component in consideration. now based on the column the user click we want to sort our model to the respective fields. the situation is different now dont you think? encapsulation helps a lot.

edit: nvm. didn;t see ur quotes. heh.

Author:  wtd [ Thu Mar 10, 2005 8:47 pm ]
Post subject: 

Something like this, you mean? Smile

code:
import List

data Column = NameCol | AgeCol | WeightCol
data Row = Row {name::Name, age::Int, weight::Int}
type Table = [Row]
 
sortByCol col =
   sortBy (\a b -> case col of
      NameCol -> compare (name a) (name b)
      AgeCol -> compare (age a) (age b)
      WeightCol -> compare (weight a) (weight b))


: