Multiple distinct objects: Difference between revisions

From Rosetta Code
Content added Content deleted
(added perl)
(markup fixes: <code> to <lang>, <tt> to <code>)
Line 9: Line 9:


=={{header|Ada}}==
=={{header|Ada}}==
<ada>
<lang ada>
A : array (1..N) of T;
A : array (1..N) of T;
</ada>
</lang>
Here N can be unknown until run-time. T is any constrained type.
Here N can be unknown until run-time. T is any constrained type.
=={{header|C}}==
=={{header|C}}==


<code c>
<lang c>
foo *foos = malloc(n * sizeof(*foos));
foo *foos = malloc(n * sizeof(*foos));
for (int i = 0; i < n; i++)
for (int i = 0; i < n; i++)
init_foo(&foos[i]);
init_foo(&foos[i]);
</code>
</lang>


(Or if no particular initialization is needed, skip that part, or use <tt>calloc</tt>.)
(Or if no particular initialization is needed, skip that part, or use <tt>calloc</tt>.)
Line 25: Line 25:
=={{header|C++}}==
=={{header|C++}}==
Using only language primitives:
Using only language primitives:
<code cpp>
<lang cpp>
// this assumes T is a default-constructible type (all built-in types are)
// this assumes T is a default-constructible type (all built-in types are)
T* p = new T[n]; // if T is POD, the objects are uninitialized, otherwise they are default-initialized
T* p = new T[n]; // if T is POD, the objects are uninitialized, otherwise they are default-initialized
Line 31: Line 31:
// when you don't need the objects any more, get rid of them
// when you don't need the objects any more, get rid of them
delete[] p;
delete[] p;
</code>
</lang>


Using the standard library
Using the standard library
<code cpp>
<lang cpp>
#include <vector>
#include <vector>


Line 48: Line 48:
for (int i = 0; i < n; ++i)
for (int i = 0; i < n; ++i)
vec3.push_back(makeDistinctObject());
vec3.push_back(makeDistinctObject());
</code>
</lang>
Instead of <tt>vector</tt>, <tt>deque</tt> or <tt>list</tt> can be used. Note that with standard containers containing the object type itself (instead of a pointer), you don't need to explicitly destroy the objects.
Instead of <code>vector</code>, <code>deque</code> or <code>list</code> can be used. Note that with standard containers containing the object type itself (instead of a pointer), you don't need to explicitly destroy the objects.


For polymorphic objects:
For polymorphic objects:
<code cpp>
<lang cpp>
#include <vector>
#include <vector>


Line 89: Line 89:
// set the pointers to NULL after deleting; again, using a smart pointer
// set the pointers to NULL after deleting; again, using a smart pointer
// would remove this need)
// would remove this need)
</code>
</lang>
Of course, also in this case one can use the other sequence containers or plain new/delete instead of <tt>vector</tt>.
Of course, also in this case one can use the other sequence containers or plain new/delete instead of <tt>vector</tt>.


=={{header|Common Lisp}}==
=={{header|Common Lisp}}==
The mistake is often written as one of these:
The mistake is often written as one of these:
<code lisp>
<lang lisp>
(make-list n :initial-element (make-the-distinct-thing))
(make-list n :initial-element (make-the-distinct-thing))
(make-array n :initial-element (make-the-distinct-thing))
(make-array n :initial-element (make-the-distinct-thing))
</code>
</lang>
which are incorrect since <tt>(make-the-distinct-thing)</tt> is only evaluated once. A common correct version is:
which are incorrect since <code>(make-the-distinct-thing)</code> is only evaluated once. A common correct version is:
<code lisp>
<lang lisp>
(loop repeat n collect (make-the-distinct-thing))
(loop repeat n collect (make-the-distinct-thing))
</code>
</lang>
which evaluates <tt>(make-the-distinct-thing)</tt> <var>n</var> times and collects each result in a list.
which evaluates <code>(make-the-distinct-thing)</code> <var>n</var> times and collects each result in a list.


=={{header|Haskell}}==
=={{header|Haskell}}==


Below, we are assuming that <tt>makeTheDistinctThing</tt> is a monadic expression (i.e. it has type <tt>m a</tt> where <tt>m</tt> is some monad, like <tt>IO</tt> or <tt>ST</tt>), and we are talking about distinctness in the context of the monad. Otherwise, this task is pretty meaningless in Haskell, because Haskell is referentially transparent (so two values that are equal to the same expression are necessarily not distinct) and all values are immutable.
Below, we are assuming that <tt>makeTheDistinctThing</tt> is a monadic expression (i.e. it has type <code>m a</code> where <code>m</code> is some monad, like <code>IO</code> or <code>ST</code>), and we are talking about distinctness in the context of the monad. Otherwise, this task is pretty meaningless in Haskell, because Haskell is referentially transparent (so two values that are equal to the same expression are necessarily not distinct) and all values are immutable.
<code haskell>
<lang haskell>
replicateM n makeTheDistinctThing
replicateM n makeTheDistinctThing
</code>
</lang>
in an appropriate do block. If it is distinguished by, say, a numeric label, one could write
in an appropriate do block. If it is distinguished by, say, a numeric label, one could write
<code haskell>
<lang haskell>
mapM makeTheDistinctThing [1..n]
mapM makeTheDistinctThing [1..n]
</code>
</lang>


An incorrect version:
An incorrect version:
<code haskell>
<lang haskell>
do x <- makeTheDistinctThing
do x <- makeTheDistinctThing
return (replicate n x)
return (replicate n x)
</code>
</lang>


=={{header|Java}}==
=={{header|Java}}==
{{works with|Java|1.5+}}
{{works with|Java|1.5+}}
simple array:
simple array:
<code java>
<lang java>
Foo[] foos = new Foo[n]; // all elements initialized to null
Foo[] foos = new Foo[n]; // all elements initialized to null
for (int i = 0; i < foos.length; i++)
for (int i = 0; i < foos.length; i++)
Line 132: Line 132:
Foo[] foos_WRONG = new Foo[n];
Foo[] foos_WRONG = new Foo[n];
Arrays.fill(foos, new Foo()); // new Foo() only evaluated once
Arrays.fill(foos, new Foo()); // new Foo() only evaluated once
</code>
</lang>


simple list:
simple list:
<code java5>
<lang java5>
List<Foo> foos = new ArrayList<Foo>();
List<Foo> foos = new ArrayList<Foo>();
for (int i = 0; i < n; i++)
for (int i = 0; i < n; i++)
Line 142: Line 142:
// incorrect:
// incorrect:
List<Foo> foos_WRONG = Collections.nCopies(n, new Foo()); // new Foo() only evaluated once
List<Foo> foos_WRONG = Collections.nCopies(n, new Foo()); // new Foo() only evaluated once
</code>
</lang>


Generic version for class given at runtime:
Generic version for class given at runtime:


It's not pretty but it gets the job done. The first method here is the one that does the work. The second method is a convenience method so that you can pass in a <tt>String</tt> of the class name. When using the second method, be sure to use the full class name (ex: "java.lang.String" for "String"). <tt>InstantiationException</tt>s will be thrown when instantiating classes that you would not normally be able to call <tt>new</tt> on (abstract classes, interfaces, etc.).
It's not pretty but it gets the job done. The first method here is the one that does the work. The second method is a convenience method so that you can pass in a <tt>String</tt> of the class name. When using the second method, be sure to use the full class name (ex: "java.lang.String" for "String"). <tt>InstantiationException</tt>s will be thrown when instantiating classes that you would not normally be able to call <tt>new</tt> on (abstract classes, interfaces, etc.).
<code java5>
<lang java5>
public static <E> List<E> getNNewObjects(int n, Class<? extends E> c){
public static <E> List<E> getNNewObjects(int n, Class<? extends E> c){
List<E> ans = new LinkedList<E>();
List<E> ans = new LinkedList<E>();
Line 165: Line 165:
return getNNewObjects(n, Class.forName(className));
return getNNewObjects(n, Class.forName(className));
}
}
</code>
</lang>


=={{header|OCaml}}==
=={{header|OCaml}}==
Line 171: Line 171:


Incorrect:
Incorrect:
<code ocaml>
<lang ocaml>
Array.make n (new foo);; (* here (new foo) can be any expression that returns a new object, record, array, or string *)
Array.make n (new foo);; (* here (new foo) can be any expression that returns a new object, record, array, or string *)
</code>
</lang>
which is incorrect since <tt>new foo</tt> is only evaluated once. A correct version is:
which is incorrect since <code>new foo</code> is only evaluated once. A correct version is:
<code ocaml>
<lang ocaml>
Array.init n (fun _ -> new foo);;
Array.init n (fun _ -> new foo);;
</code>
</lang>


=={{header|Perl}}==
=={{header|Perl}}==
incorrect:
incorrect:
<code perl>
<lang perl>
(Foo->new) x $n # here Foo->new can be any expression that returns a reference representing a new object
(Foo->new) x $n # here Foo->new can be any expression that returns a reference representing a new object
</code>
</lang>
which is incorrect since <tt>Foo->new</tt> is only evaluated once.
which is incorrect since <code>Foo->new</code> is only evaluated once.


A correct version is:
A correct version is:
<code perl>
<lang perl>
map { Foo->new } 1 .. $n;
map { Foo->new } 1 .. $n;
</code>
</lang>
which evaluates <tt>Foo->new</tt> <var>$n</var> times and collects each result in a list.
which evaluates <tt>Foo->new</tt> <var>$n</var> times and collects each result in a list.


=={{header|Python}}==
=={{header|Python}}==
The mistake is often written as:
The mistake is often written as:
<code python>
<lang python>
[Foo()] * n # here Foo() can be any expression that returns a new object
[Foo()] * n # here Foo() can be any expression that returns a new object
</code>
</lang>
which is incorrect since <tt>Foo()</tt> is only evaluated once. A common correct version is:
which is incorrect since <tt>Foo()</tt> is only evaluated once. A common correct version is:
<code python>
<lang python>
[Foo() for i in xrange(n)]
[Foo() for i in xrange(n)]
</code>
</lang>
which evaluates <tt>Foo()</tt> <var>n</var> times and collects each result in a list. This last form is also discussed [[Two-dimensional array (runtime)#Python|here]], on the correct construction of a two dimensional array.
which evaluates <tt>Foo()</tt> <var>n</var> times and collects each result in a list. This last form is also discussed [[Two-dimensional array (runtime)#Python|here]], on the correct construction of a two dimensional array.


=={{header|Ruby}}==
=={{header|Ruby}}==
The mistake is often written as one of these:
The mistake is often written as one of these:
<code ruby>
<lang ruby>
[Foo.new] * n # here Foo.new can be any expression that returns a new object
[Foo.new] * n # here Foo.new can be any expression that returns a new object
Array.new(n, Foo.new)
Array.new(n, Foo.new)
</code>
</lang>
which are incorrect since <tt>Foo.new</tt> is only evaluated once. A common correct version is:
which are incorrect since <code>Foo.new</code> is only evaluated once. A common correct version is:
<code ruby>
<lang ruby>
Array.new(n) { Foo.new }
Array.new(n) { Foo.new }
</code>
</lang>
which evaluates <tt>Foo.new</tt> <var>n</var> times and collects each result in an Array. This last form is also discussed [[Two-dimensional array (runtime)#Ruby|here]], on the correct construction of a two dimensional array.
which evaluates <code>Foo.new</code> <var>n</var> times and collects each result in an Array. This last form is also discussed [[Two-dimensional array (runtime)#Ruby|here]], on the correct construction of a two dimensional array.

Revision as of 12:44, 30 January 2009

Task
Multiple distinct objects
You are encouraged to solve this task according to the task description, using any language you may know.

Create a sequence (array, list, whatever) consisting of n distinct items of the same type. n should be determined at runtime.

By distinct we mean that if they are mutable, changes to one do not affect all others; if there is an appropriate equality operator they are considered unequal; etc. The code need not specify a particular kind of distinction, but do not use e.g. a numeric-range generator which does not generalize.

This task was inspired by the common error of intending to do this, but instead creating a sequence of nreferences to the same mutable object; it might be informative to show the way to do that as well.

This task mostly makes sense for languages operating in the pass-references-by-value style (most object-oriented or 'dynamic' languages).

Ada

<lang ada> A : array (1..N) of T; </lang> Here N can be unknown until run-time. T is any constrained type.

C

<lang c> foo *foos = malloc(n * sizeof(*foos)); for (int i = 0; i < n; i++)

 init_foo(&foos[i]);

</lang>

(Or if no particular initialization is needed, skip that part, or use calloc.)

C++

Using only language primitives: <lang cpp> // this assumes T is a default-constructible type (all built-in types are) T* p = new T[n]; // if T is POD, the objects are uninitialized, otherwise they are default-initialized // ... // when you don't need the objects any more, get rid of them delete[] p; </lang>

Using the standard library <lang cpp>

  1. include <vector>

// this assumes T is default-constructible std::vector<T> vec1(n); // all n objects are default-initialized

// this assumes t is a value of type T (or a type which implicitly converts to T) std::vector<T> vec2(n, t); // all n objects are copy-initialized with t

// if you want to evaluate an expression for each new object // (e.g. if it uses randomness to initialize the state or something) std::vector<T> vec3; for (int i = 0; i < n; ++i)

 vec3.push_back(makeDistinctObject());

</lang> Instead of vector, deque or list can be used. Note that with standard containers containing the object type itself (instead of a pointer), you don't need to explicitly destroy the objects.

For polymorphic objects: <lang cpp>

  1. include <vector>

// this assumes Base is a polymorphic type which has a clone method for polymorphic copying, // and p is a pointer to Base or to a type derived from Base.

// the following is NOT correct: std::vector<Base*> bvec_WRONG(n, p); // create n copies of p, which all point to the same opject p points to.

// nor is this: std::vector<Base*> bvec_ALSO_WRONG(n, p->clone()); // create n pointers to a single clone of *p

// the correct solution std::vector<Base*> bvec(n); for (int i = 0; i < n; ++i)

 bvec[i] = p->clone();     // "p->clone()" here can be replaced with any expression returning a pointer to a new object

// another correct solution // this solution avoids uninitialized pointers at any point std::vector<Base*> bvec2; for (int i = 0; i < n; ++i)

 bvec2.push_back(p->clone()); // "p->clone()" here can be replaced with any expression returning a pointer to a new object

// ...

// because the container contains pointers, the objects have to be explicitly deleted // because ordinary pointers don't have destructors, so can't delete themselves // using a smart pointer like boost::shared_ptr instead would make this step unnecessary for (int i = 0; i < bvec.size(); ++i)

 delete bvec[i];

// alternate iteration: for (std::vector<Base*>::iterator it = bvec2.begin(); it != bvec2.end(); ++i)

 delete *i;

bvec.clear(); // make sure the dangling pointers are not used any more bvec2.clear(); // (not necessary if bvec isn't used afterwards; alternatively,

              // set the pointers to NULL after deleting; again, using a smart pointer
              // would remove this need)

</lang> Of course, also in this case one can use the other sequence containers or plain new/delete instead of vector.

Common Lisp

The mistake is often written as one of these: <lang lisp> (make-list n :initial-element (make-the-distinct-thing)) (make-array n :initial-element (make-the-distinct-thing)) </lang> which are incorrect since (make-the-distinct-thing) is only evaluated once. A common correct version is: <lang lisp> (loop repeat n collect (make-the-distinct-thing)) </lang> which evaluates (make-the-distinct-thing) n times and collects each result in a list.

Haskell

Below, we are assuming that makeTheDistinctThing is a monadic expression (i.e. it has type m a where m is some monad, like IO or ST), and we are talking about distinctness in the context of the monad. Otherwise, this task is pretty meaningless in Haskell, because Haskell is referentially transparent (so two values that are equal to the same expression are necessarily not distinct) and all values are immutable. <lang haskell> replicateM n makeTheDistinctThing </lang> in an appropriate do block. If it is distinguished by, say, a numeric label, one could write <lang haskell> mapM makeTheDistinctThing [1..n] </lang>

An incorrect version: <lang haskell> do x <- makeTheDistinctThing

  return (replicate n x)

</lang>

Java

Works with: Java version 1.5+

simple array: <lang java> Foo[] foos = new Foo[n]; // all elements initialized to null for (int i = 0; i < foos.length; i++)

   foos[i] = new Foo();

// incorrect version: Foo[] foos_WRONG = new Foo[n]; Arrays.fill(foos, new Foo()); // new Foo() only evaluated once </lang>

simple list: <lang java5> List<Foo> foos = new ArrayList<Foo>(); for (int i = 0; i < n; i++)

   foos.add(new Foo());

// incorrect: List<Foo> foos_WRONG = Collections.nCopies(n, new Foo()); // new Foo() only evaluated once </lang>

Generic version for class given at runtime:

It's not pretty but it gets the job done. The first method here is the one that does the work. The second method is a convenience method so that you can pass in a String of the class name. When using the second method, be sure to use the full class name (ex: "java.lang.String" for "String"). InstantiationExceptions will be thrown when instantiating classes that you would not normally be able to call new on (abstract classes, interfaces, etc.). <lang java5> public static <E> List<E> getNNewObjects(int n, Class<? extends E> c){ List<E> ans = new LinkedList<E>(); try { for(int i=0;i<n;i++) ans.add(c.newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return ans; }

public static List<Object> getNNewObjects(int n, String className) throws ClassNotFoundException{ return getNNewObjects(n, Class.forName(className)); } </lang>

OCaml

For arrays:

Incorrect: <lang ocaml> Array.make n (new foo);; (* here (new foo) can be any expression that returns a new object, record, array, or string *) </lang> which is incorrect since new foo is only evaluated once. A correct version is: <lang ocaml> Array.init n (fun _ -> new foo);; </lang>

Perl

incorrect: <lang perl> (Foo->new) x $n # here Foo->new can be any expression that returns a reference representing a new object </lang> which is incorrect since Foo->new is only evaluated once.

A correct version is: <lang perl> map { Foo->new } 1 .. $n; </lang> which evaluates Foo->new $n times and collects each result in a list.

Python

The mistake is often written as: <lang python> [Foo()] * n # here Foo() can be any expression that returns a new object </lang> which is incorrect since Foo() is only evaluated once. A common correct version is: <lang python> [Foo() for i in xrange(n)] </lang> which evaluates Foo() n times and collects each result in a list. This last form is also discussed here, on the correct construction of a two dimensional array.

Ruby

The mistake is often written as one of these: <lang ruby> [Foo.new] * n # here Foo.new can be any expression that returns a new object Array.new(n, Foo.new) </lang> which are incorrect since Foo.new is only evaluated once. A common correct version is: <lang ruby> Array.new(n) { Foo.new } </lang> which evaluates Foo.new n times and collects each result in an Array. This last form is also discussed here, on the correct construction of a two dimensional array.