Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Is there a language where collections can be used as objects without altering the behavior?

As an example, first, imagine those functions work:

function capitalize(str) 
    //suppose this *modifies* a string object capitalizing it
function greet(person):
    print("Hello, " + person)

capitalize("pedro")
>> "Pedro"

greet("Pedro")
>> "Hello, Pedro"

Now, suppose we define a standard collection with some strings:

people = ["ed","steve","john"]

Then, this will call toUpper() on each object on that list

people.toUpper() 
>> ["Ed","Steve","John"]

And this will call greet once for EACH people on the list, instead of sending the list as argument

greet(people)
>> "Hello, Ed"
>> "Hello, Steve"
>> "Hello, John"
share|improve this question
3  
The only language feature you need is LISP's map. You would do something like (map toUpper arr) in Clojure. Forgive me if I got the order wrong. Everything else should be built as a library. Just adding auto map to a language is not a good idea - it does not give you flexibility. What about upper-casing every second item? A powerful library such as LINQ or python's itertools or basic lisp primitives can let you do that. Anyhow, I have not heard of such language, thank God (I second DeadMG's opinion). –  Job Jun 3 '12 at 22:15
    
I think your reasoning is an really great, but I don't think it would not give you flexibility. Upper-casing every second object would be spelled as each_2(people).toUpper() or the like. –  Dokkat Jun 3 '12 at 23:26
2  
birds = [myBird1, myBird2, myBird3]; birds.fly(); This is superior to the so-common and repetitive "for (bird in birds): bird.fly()" (in Python, that is already the shortest way to write this). What I mean is that doing something with a group of elements is more common than calling array methods (such as .sort, .push) and thus array.method should cast the method for each element, and the today standard array.sort should be spelled as sort(array) instead. I don't see why it would cause any problem in any way. –  Dokkat Jun 4 '12 at 1:46
1  
Oh, and for the function application part, kill(birds) is, too, more readable than for bird in birds: kill(bird), so it should be the standard behavior. If you want to send a array to a function (this is not so common) you could anotate as foo([birds]), which I don't see as problematic, at all, and would actually even add further to readability, even for unrelated cases. –  Dokkat Jun 4 '12 at 1:49
1  
So, it should not be part of the language. It is just rarely used. There are lots of other standard features that a language might need first. Another point - it forces something down peoples throats that they might not necessarily like. Even Python's white space mandate causes quite a bit of controversy. Suppose C# supported the syntax that you speak of. Also suppose I had an extension method public static void Print(this IList<string> strs) then the "auto-map" feature would conflict with MY EXTENSION METHOD - a feature I find much more valuable. If I can use a map, then why have 2 ways? –  Job Jun 4 '12 at 3:22

3 Answers 3

up vote 18 down vote accepted

Yes, there are such languages. Many of them.

In fact, this feature is pretty much the definition of an array language or vector language. Examples of array and vector languages include, but are not limited to, the APL family of languages with its successors, derivatives and cousins (E.g. APL, J, K) and pretty much all mathematical and statistical languages such as Mathematica, MATLAB, Octave, R, and S.

Fortran 90 and Ada also have this feature, as does Fortress.

Interestingly, many modern CPUs also support vector programming, e.g. the x86 architecture with the MMX, SSE, SSE2, SSE3 (Intel) and 3DNow! (AMD) instruction sets, the POWER and PowerPC architectures with the VMX and AltiVec instruction sets, Sparc, MIPS, even ARM.

The language by Microsoft Research has the concept of streams (roughly similar to IEnumerable). Streams pretty much work exactly as you describe. Here's an example from the Cω documentation (emphasis mine):

A key programming feature of Cω is generalized member access: the familiar 'dot' operator is now much more powerful. Thus if the receiver is a stream, then the member access is mapped over the elements, e.g. zones.ToString() implicitly maps the method call over the elements of the stream zones and returns a value of type string*. This feature significantly reduces the burden on the programmer.

A very interesting property of this kind of programming is that it not only allows you to semantically think of "applying an operation to all elements at once", it also allows the language implementor to implement it by literally applying an operation to all elements at once, IOW in parallel.

share|improve this answer
5  
This is the kind of answer that encorages me using Stack, when everyone just attacked the idea or said with certainty it does not exist (why?). I have much to explore now. Thank you. –  Dokkat Jun 4 '12 at 5:36
    
@Dokkat: Thanks for the kind words. I try my best. –  Jörg W Mittag Jun 5 '12 at 10:16
    
Sorry for not choosing your answer before, guess I forgot. –  Dokkat Jun 20 '12 at 4:46
    
I would also add Numpy/Scipy Python libraries to the list: numpy.scipy.org –  peterhil Jul 23 '12 at 21:21

You can get semantics very similar to what you're asking for in nearly all languages using the composite pattern.

Given you have some type similar to this:

// pseudocode
class CustomString
{
    CustomString Composite;
    string Value;
}

... and a Greet method like this:

// pseudocode
public string Greet(CustomString cs)
{
    string ret;
    if (cs!= null)
        ret += "Hello " + cs.Value + newline;

    if (cs.Composite != null)
        ret += Greet(cs.Composite);
}

... you can make calls like this:

writeln(Greet(new CustomString("snorfys")))
>> Hello snorfys

cs = new CustomString("snorfys") { Composite = new CustomString("Dokkat") }
writeln(Greet(cs))
>> Hello snorfys
>> Hello Dokkat

If you do a lot of work with trees, programming in this way feels common quickly (that is to say that each tree node is, and can be treated as, a subtree).

share|improve this answer
1  
I'm trying to understand what you've done there? I should read about that pattern. –  Dokkat Jun 4 '12 at 6:17

In C# for example there are extensions (add the functionality to the collection - underneath it would still be a loop, but nothing visible) and Linq - example:

public static IEnumerble<string> Capitalize(this IEnumerable<string> collection)
{
   var List<string> rtn = new List<string>(collection.Count());
   foreach (var item in collection) 
   {
      var ci = Thread.CurrentThread.CurrentCulture; 
      var textInfo = ci.TextInfo; 

      rtn.Add(textInfo.ToTitleCase(item)); 
   }
   return rtn;
}

[Note: I hand keyed this - so maybe some typos errors]

alternatively, ...

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{  
   source.ThrowIfNull("source");     
   action.ThrowIfNull("action");    
   foreach (T element in source)    
   {         
        action(element);     
   } 
} 

with a function for capitalize

public static string Capitalize(this string str)
{
    var ci = Thread.CurrentThread.CurrentCulture; 
    var textInfo = ci.TextInfo; 

    return textInfo.ToTitleCase(str); 
 }

and then

myColl.ForEach(x => x.Capitalize()); 

The difference is the second allows you to pass any function along and for any collection type.

myCollection.Where(employee => emplyee.Age > 50).ForEach(employee => employee.Fire());

works too (in a heartless sort of way :D )

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.