Multiple distinct objects

From Rosetta Code
Revision as of 09:51, 13 July 2011 by rosettacode>Markhobley ({{omit from|GUISS}})
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, initialized 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.

By initialized we mean that each item must be in a well-defined state appropriate for its type, rather than e.g. arbitrary previous memory contents in an array allocation. Do not show only an initialization technique which initializes only to "zero" values (e.g. calloc() or int a[n] = {}; in C), unless user-defined types can provide definitions of "zero" for that type.

This task was inspired by the common error of intending to do this, but instead creating a sequence of n references to the same mutable object; it might be informative to show the way to do that as well, both as a negative example and as how to do it when that's all that's actually necessary.

This task is most relevant to languages operating in the pass-references-by-value style (most object-oriented, garbage-collected, and/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. In Ada all objects are always initialized, though some types may have null initialization. When T requires a non-null initialization, it is done for each array element. For example, when T is a task type, N tasks start upon initialization of A. Note that T can be a limited type like task. Limited types do not have predefined copy operation. Arrays of non-limited types can also be initialized by aggregates of: <lang ada>A : array (1..N) of T := (others => V);</lang> Here V is some value or expression of the type T. As an expression V may have side effects, in that case it is evaluated exactly N times, though the order of evaluation is not defined. Also an aggregate itself can be considered as a solution of the task: <lang ada>(1..N => V)</lang>

ALGOL 68

Translation of: python
Works with: ALGOL 68 version Standard - no extensions to language used
Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386
Works with: ELLA ALGOL 68 version Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386

<lang algol68>MODE FOO = STRUCT(CHAR u,l); INT n := 26; [n]FOO f;

  1. Additionally each item can be initialised #

FOR i TO UPB f DO f[i] := (REPR(ABS("A")-1+i), REPR(ABS("a")-1+i)) OD;

print((f, new line))</lang> Output:

AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz

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++

By default C++ has value semantics, so this problem does not present itself unless the programmer deliberately choses to refer to objects though a pointer. Examples are given for both cases.

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

//If default initialisation is not what you want, or if T is a POD type which will be uninitialized for(size_t i = 0; i != n; ++i)

  p[i] = make_a_T(); //or some other expression of type T

// when you don't need the objects any more, get rid of them delete[] p;</lang>

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

  1. include <algorithm>
  2. include <iterator>

// 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

// To initialise each value differently std::generate_n(std::back_inserter(vec), n, makeT); //makeT is a function of type T(void) </lang>

In C++ reference semantics are achieved by holding objects by pointer. Here is an example of the error, and a correct way of achieving distinctness.

These examples assume T has a public copy constructor, and that p is a pointer to T;

<lang cpp>#include <vector>

  1. include <tr1/memory>

using namespace std; using namespace std::tr1;

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

// nor is this: std::vector<TPtr_t> bvec_ALSO_WRONG(n, TPtr_t(new T(*p)) ); // create n pointers to a single copy of *p

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

 bvec[i] = TPtr_t(new T(*p); //or any other call to T's constructor

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

 bvec2.push_back(TPtr_t(new T(*p)); 

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

C#

<lang csharp>using System; using System.Linq; using System.Collections.Generic;

List<Foo> foos = Enumerable.Range(1, n).Select(x => new Foo()).ToList();</lang>

Clojure

An example using pseudo-random numbers: <lang clojure>user> (take 3 (repeat (rand))) ; repeating the same random number three times (0.2787011365537204 0.2787011365537204 0.2787011365537204) user> (take 3 (repeatedly rand)) ; creating three different random number (0.8334795669220695 0.08405601245793926 0.5795448744634744) user></lang>

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 the form (make-the-distinct-thing) is only evaluated once and the single object is put in every position of the sequence. A commonly used 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.

It is also possible to use map-into, the destructive map operation, to do this since it may take zero input sequences; this method can produce any sequence type, such as a vector (array) rather than a list, and takes a function rather than a form to specify the thing created:

<lang lisp>(map-into (make-list n) #'make-the-distinct-thing) (map-into (make-array n) #'make-the-distinct-thing)</lang>

D

For reference types (classes): <lang d>foo[]foo_array; foo_array.length = n; foreach(ref item;foo_array) {

 item = new foo;

}</lang> For value types: <lang d>foo[]foo_array; foo_array.length = n; foo_array[] = initializer_value;</lang>

E

E needs development of better map/filter/stream facilities. The easiest way to do this so far is with the accumulator syntax, which is officially experimental because we're not satisfied with it as yet.

<lang e>pragma.enable("accumulator") ...

accum [] for _ in 1..n { _.with(makeWhatever()) }</lang>

Factor

clone is the important word here to have distinct objects. This creates an array of arrays. <lang factor>1000 [ { 1 } clone ] replicate</lang>

Fortran

<lang fortran> program multiple

 ! Define a simple type
 type T
    integer :: a = 3
 end type T
 ! Define a type containing a pointer
 type S
    integer, pointer :: a
 end type S
 type(T), allocatable :: T_array(:)
 type(S), allocatable :: S_same(:)
 integer              :: i
 integer, target      :: v
 integer, parameter   :: N = 10
 ! Create 10 
 allocate(T_array(N))
 ! Set the fifth one to b something different
 T_array(5)%a = 1
 ! Print them out to show they are distinct
 write(*,'(10i2)') (T_array(i),i=1,N)
 ! Create 10 references to the same object
 allocate(S_same(N))
 v = 5
 do i=1, N
    allocate(S_same(i)%a)
    S_same(i)%a => v
 end do
 ! Print them out - should all be 5
 write(*,'(10i2)') (S_same(i)%a,i=1,N)
 ! Change the referenced object and reprint - should all be 3
 v = 3
 write(*,'(10i2)') (S_same(i)%a,i=1,N)  

end program multiple </lang>

F#

The wrong way: <lang fsharp>>List.replicate 3 (System.Guid.NewGuid());;

val it : Guid list =

 [485632d7-1fd6-4d9e-8910-7949d7b2b485; 485632d7-1fd6-4d9e-8910-7949d7b2b485;
  485632d7-1fd6-4d9e-8910-7949d7b2b485]</lang>

The right way: <lang fsharp>> List.init 3 (fun _ -> System.Guid.NewGuid());;

val it : Guid list =

 [447acb0c-092e-4f85-9c3a-d369e4539dae; 5f41c04d-9bc0-4e96-8165-76b41fe8cd93;
  1086400c-72ff-4763-9bb9-27e17bd4c7d2]</lang>

Go

Useful: <lang go>func nxm(n, m int) [][]int {

   d2 := make([][]int, n)
   for i := range d2 {
       d2[i] = make([]int, m)
   }
   return d2

}</lang> Probably not what the programmer wanted: <lang go>func nxm(n, m int) [][]int {

   d1 := make([]int, m)
   d2 := make([][]int, n)
   for i := range d2 {
       d2[i] = d1
   }
   return d2

}</lang>

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>

Icon and Unicon

An incorrect approach uses, e.g., the list constructor procedure with an initial value:

<lang Icon>

 items_wrong := list (10, [])
 # prints '0' for size of each item
 every item := !items_wrong do write (*item)
 # after trying to add an item to one of the lists
 push (items_wrong[1], 2)
 # now prints '1' for size of each item
 every item := !items_wrong do write (*item)

</lang>

A correct approach initialises each element separately:

<lang Icon>

 items := list(10)
 every i := 1 to 10 do items[i] := []

</lang>

J

<lang J>i.</lang>

J almost always uses pass-by-value, so this topic is not very relevant to J.

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());//can't call new on generic classes } 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>

JavaScript

<lang javascript>var a = new Array(n); for (var i = 0; i < n; i++)

 a[i] = new Foo();</lang>

Modula-3

This example is incorrect. Please fix the code and remove this message.

Details: It does not initialize the sequence.

Similar to the Ada version above: <lang modula3>VAR a: ARRAY OF T</lang> This creates an open array (an array who's size is not known until runtime) of distinct elements of type T.

Modula-3 does not define what values the elements of A have, but it does guarantee that they will be of type T.

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>

Oz

With lists, it is difficult to do wrong. <lang oz>declare

 Xs = {MakeList 5} %% a list of 5 unbound variables

in

 {ForAll Xs OS.rand} %% fill it with random numbers (CORRECT)
 {Show Xs}</lang>

With arrays on the other hand, it is easy to get wrong: <lang oz>declare

 Arr = {Array.new 0 10 {OS.rand}} %% WRONG: contains ten times the same number

in

 %% CORRECT: fill it with ten (probably) different numbers
 for I in {Array.low Arr}..{Array.high Arr} do
    Arr.I := {OS.rand}
 end</lang>

Perl

incorrect: <lang perl>(Foo->new) x $n

  1. here Foo->new can be any expression that returns a reference representing
  2. 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.

Perl 6

Just like in Perl 5, the list repetition operator evaluates the statement only once, so

<lang perl6># WRONG my @a = Foo.new xx $n;</lang>

produces $n references to the same object. This works instead:

<lang perl6>my @a = map { Foo.new }, ^$n</lang>

PicoLisp

Create 5 distinct (empty) objects: <lang PicoLisp>: (make (do 5 (link (new)))) -> ($384717187 $384717189 $384717191 $384717193 $384717195)</lang> Create 5 anonymous symbols with the values 1 .. 5: <lang PicoLisp>: (mapcar box (range 1 5)) -> ($384721107 $384721109 $384721111 $384721113 $384721115)

(val (car @))

-> 1

(val (cadr @@))

-> 2</lang>

PureBasic

<lang PureBasic>n=Random(50)+25 Dim A.i(n)

Creates a Array of n [25-75] elements depending on the outcome of Random().
Each element will be initiated to zero.

For i=0 To ArraySize(A())

 A(i)=2*i

Next i

Set each individual element at a wanted (here 2*i) value and
automatically adjust accordingly to the unknown length of the Array.

NewList *PointersToA() For i=0 To ArraySize(A())

 AddElement(*PointersToA())
 *PointersToA()=@A(i)

Next

Create a linked list of the same length as A() above.
Each element is then set to point to the Array element
of the same order.

ForEach *PointersToA()

 Debug PeekI(*PointersToA())

Next

Verify by sending each value of A() via *PointersToA()
to the debugger's output.</lang>

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.

R

The mistake is often written as: <lang r>rep(foo(), n) # foo() is any code returning a value</lang> A common correct version is: <lang r>replicate(n, foo())</lang> which evaluates foo() n times and collects each result in a list. (Using simplify=TRUE lets the function return an array, where possible.)

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, and thus you now have n references to the same object. 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.

Scala

Yielding a normal class instance here (rather than a case class instance), as case objects are identical if created with the same constructor arguments.

<lang scala>for (i <- (0 until n)) yield new Foo()</lang>

Smalltalk

<lang smalltalk>|c| "Create an ordered collection that will grow while we add elements" c := OrderedCollection new. "fill the collection with 9 arrays of 10 elements; elements (objects)

are initialized to the nil object, which is a well-defined 'state'"

1 to: 9 do: [ :i | c add: (Array new: 10) ]. "However, let us show a way of filling the arrays with object number 0" c := OrderedCollection new. 1 to: 9 do: [ :i | c add: ((Array new: 10) copyReplacing: nil withObject: 0) ]. "demonstrate that the arrays are distinct: modify the fourth of each" 1 to: 9 do: [ :i | (c at: i) at: 4 put: i ]. "show it" c do: [ :e | e printNl ].</lang>

Tcl

Tcl values are implemented using copy-on-write reference semantics with no (exposed) mechanism for determining whether two values are really references to the same value, which makes this task relatively moot. However, in the case where there is a collection of objects it becomes important to perform the construction correctly (i.e., repeatedly) otherwise it is just the name of the object that will be copied when it is written to.

Works with: Tcl version 8.6

or

Library: TclOO

<lang Tcl>package require TclOO

  1. The class that we want to make unique instances of

set theClass Foo

  1. Wrong version; only a single object created

set theList [lrepeat $n [$theClass new]]

  1. Right version; objects distinct

set theList {} for {set i 0} {$i<$n} {incr i} {

   lappend theList [$theClass new]

}</lang>