From the standpoint of pure computer science (or perhaps computational linguisticis), I would like to know the difference between the words:
Various Languages utilize these words and functionality in difference ways. In Python, for example, Decorators [according to the Python Wiki] (emphasis mine):
Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated.
This strikes me as being remarkably similar to an Aspect Oriented Programming Tool like PostSharp or DynamicProxy. i.e.:
[Profile]
private static void SleepSync()
{
Thread.Sleep(200);
}
Source: PostSharp Examples
In C# and Java (as well as a myriad of other languages), attributes can either mean a Decorator-ish pattern (C#) or a field (Java).
And in C++ via boost or PhP via the builtin trait word, we can use traits to extend classes as shown here: https://en.wikipedia.org/wiki/Trait_(computer_programming)
So, from a "pure" standpoint, what is the canonical definitions of what all these actually are? Is there a better way to define them?
Parts of aspect-oriented programming (AOP) are implemented by decorators in Python. Our purpose here is to leverage a few aspect-oriented concepts to help show the purpose of decorators and mixins in Python. The idea of a cross-cutting concern is central to AOP.
Decorators provide a simple syntax for calling higher-order functions. By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.
The decorator design pattern is a structural pattern, which provides a wrapper to the existing class. The decorator design pattern uses abstract classes or interfaces with the composition to implement the wrapper.
A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.
Decorator
I think of Decorator in terms of the design pattern. Design patterns are recognized in many languages, particularly object oriented ones. The decorator as a pattern, then, is a wrapper that adds functionality not present in the function or class being decorated.
The simplest example I can think of is a decorator function. The function
int foo(int x)
could be decorated by another function that accepts a second parameter, does something else with it, and then in turn calls foo(), passing the original parameter x.
int bar(int x, int y) {
return y*y + foo(x);
}
While design patterns are typically applied at the class level, the principle here is the same, and I think it illustrates well what is meant by a decorator. Whether each particular language adheres to this is a different matter. One language might have something else that it calls a 'decorator' - but to me this concept best matches the idea of decorating something plain with additional functionality, without altering the original code or even using inheritance.
Another common example are the I/O classes in Java. There is the basic
OutputStream s
and then you can decorate this by using the more specialized classes depending on the type of data being dealt with, or the format you wish to read the data in:
OutputStream s1 = new FileOutputStream("somefile.txt");
or
OutputStream s2 = new ByteOutputStream("rawdata.hex");
Attribute
I would lean towards the C# idea of attribute being the correct understanding, because it is different from a decorator. An attribute assigns a semantic value which can vary from one use to another, and even between API's which use the same attribute. For example, I might have two functions:
[Logging] private void a() { ... }
[Security] private void b() { ... }
I can assign one a logging attribute and one a security attribute, and what those attributes mean might be different to client API's that examine those attributes. One might use log4j to implement the logging and one might use another API. The definition here is much more fluid and open to interpretation by different parties or users of my code. One could certainly use an attribute to act as a decorator, but attributes can be used for much more than that.
Just for disambiguation, the word attribute is also used to denote member variables of a class. Here we are talking about the larger, more abstract concept of assigning a predefined semantic value to an existing object or class. Java calls these annotations.
One qualifier in my mind for it being an Attribute, in the sense we are talking about, is that it doesn't directly modify behavior, only indirectly. For example, assigning the [Logging] attribute to something doesn't change its code in any way. It's like attaching a name tag which others are looking for. When another program or application sees the name tag, it infers certain things and may change its behavior accordingly. But (at least in Java) annotations or attributes do not directly modify anything - again, just a name tag. This may be slightly different in C# or other languages that support attributes, in which case I would consider them to be a more advanced attribute or something else entirely.
Aspect
An aspect in the sense of aspect-oriented programming (AOP) is a sort of self-modifying or self-updating code construct. It defines a section of code as more malleable (a point cut) and allows that particular section to be swapped in and out between one or more possible updates, patches, or different versions of the same section of code.
Could you do some of the same things as decorators and attributes using aspects? Sure. But why would you give yourself that headache? AOP is like the next step up from OOP, only it should be used when necessary. When is it necessary? When a particular application has a lot of "cross-cutting concerns" like security or logging - for example, a banking application. These concerns cross-cut; they cross beyond the traditional boundaries which make nice defined classes and packages. When you are logging, it doesn't do a lot of good unless you log everything; hence, this concern is cross-cutting. So when you go to update one class's logging mechanism, it would be difficult to simultaneously modify all other classes and API's, but it would also be necessary. Otherwise your logging is now inconsistent and confusing, and more difficult to use for troubleshooting or monitoring.
To make these kinds of updates less of a headache, aspect oriented languages like AspectJ were introduced. I haven't run across an "aspect" that meant anything other than this, but there may be some as stated earlier about decorators. A particular language might call something an aspect, but it might look more like one of the other things we have already discussed.
Trait
Trait is synonymous with interface, or at least that's how it appears to be in the languages I've studied.
An interface is an OOP concept which declares behaviors without implementing them. Creating these expected behaviors allow those behaviors to become generic, and to be invoked generically without caring about specifics. It's left to the subclasses to implement them.
The classic OOP example is Animal, with two subclasses, Cat and Dog.
public interface/trait Animal {
public void speak();
}
public class Cat implements Animal {
public void speak() {
output("Meow.");
}
}
public class Dog implements Animal {
public void speak() {
output("Bark!");
}
}
This is also a great example of polymorphism - one of those words that tend to make non-computer folks cringe. It just means that cat and dog have individual behaviors, and if I declare an Animal object, I don't care what kind you give me. You can give me a cat or a dog. Because both are animals, in either case, all I have to do is call the speak() function of my Animal object, and I can rest assured that the correct result will occur in either case. Each individual subclass knows what it needs to do. In C++ the waters are a little more muddy here, but the general concept is the same (read into the keyword 'virtual' if you want to start down that rabbit hole).
Wrap-Up
I hope that clears up some of the confusion. It seems that, as you said, many different languages have many different meanings for each of these, no doubt contributing to the confusion. I believe that if you look into it further, you will find that by and large, these are the standard meanings. I have been programming in many languages (VB, C++, C#, Java, Paschal, PHP, Perl) for 18+ years and these are the definitions I am most comfortable with believing as a kind of standard.
I certainly welcome further discussion on what I have said.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With