Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Is it Really Better to 'Return an Empty List Instead of null'? - Part 2

0.00/5 (No votes)
17 Dec 2014 1  
This article aims to answer the question: Should we return an empty list or 'null' from functions?

Introduction

Welcome to part 2 of the article series Is it really better to 'return an empty list instead of null'?. Part 1 introduced the popular advice 'return an empty list instead of null' which is widely accepted and supported by leaders in the software industry. We looked at a source code example that demonstrates the rationale. Finally, there was a hint that the advice might need to be reconsidered.

In this part, we are going to compare both approaches (i.e., return an empty list vs return null) by looking at concrete source code examples of both approaches and examining their pros and cons.

Part II: Comparison of the Two Approaches

Two Opposite Approaches

Many functions in software programs return collections (sets, lists, maps, arrays, strings, etc). The question we are interested in is this: What should such a function return if there are no data to return. For example, what should the following method return if there are no children in the classroom:

public static List<Child> getChildrenInClassRoom()

We will compare two approaches:

  • Return an empty collection

    We'll call this the avoid-null approach.

  • Return null

    We'll call this the love-null approach.

There exist alternative approaches, but we will not discuss them here. For example, we could use the Optional/Maybe pattern. This pattern has already been discussed in my previous article Why We Should Love 'null' (see section 'The Optional/Maybe Pattern').

Moreover, in this part, we will not consider the case of throwing an exception if the function's operation cannot be executed properly (e.g. invalid input arguments, resource error, etc.).

The goal is to keep things simple and to just focus on returning an empty collection versus returning null.

For each approach, we will consider:

  • Software reliability
  • Time and space requirements
  • API differences

Software Reliability Considerations

The aim of this chapter is to answer a crucial question:

Does one of the two approaches help us to write more reliable software?

In other words:

Do we increase the risk for severe bugs if we choose one approach over the other?

Let us start with a really simple example.

Listing Elements in a Collection

Suppose we want to print the list of orders of a customer. We use the following method to retrieve all orders of a given customer:

public static List<ICustomerOrder> getOrdersByCustomer ( String customerID )

To print the list, we could write code like this:

String customerID = "123";
for ( ICustomerOrder order : getOrdersByCustomer ( customerID ) ) {
   System.out.println ( order.getID() + " | " + order.getAmount().toString() );
}

If orders exist for customer "123", then the output would look like this:

12034 | 127.87
15677 | 238.93

So far so good.

But what happens if no orders exist for the customer?

In the avoid-null world, getOrdersByCustomer() returns an empty list. So, our code still runs and nothing is displayed.

In the love-null world getOrdersByCustomer() returns null and this causes a NullPointerException, thrown in the for statement.

And that's exactly why proponents of the avoid-null approach avoid null and return an empty list. They claim:

Your client code is more simple and work in all situations. You don't have to check for null and you eliminate the risk for a null pointer error. And in cases you really need to check for 'no data' you have isEmpty() (e.g. if ( list.isEmpty() ) {).

In a nutshell: Your code is simpler and less error-prone.

However, let us now consider the end-user. How would the user of our mini-application experience the case 'no data'?

In a more elaborated version of our application, the user would be prompted for a customer ID. He/she enters "123" and then waits for the result.

In the love-null world, the application crashes with a null pointer error. That's not good!

In the avoid-null world, one of the following could happen, depending on how the result is displayed:

  • nothing is displayed in the system console or
  • the browser displays an empty table (i.e. a white screen) or
  • a blank page of paper is printed out.
Empty list of customer orders

List of customer orders

The user will be surprised and wonder: What does this mean: Are there no orders for the customer or is there a problem with my computer?

No doubt that this is less frustrating than an application crash.

However, what the user really wants is a clear and unambiguous message like:

No orders yet for customer 123.
[Note] Note
I got the idea for this example because I experienced this situation (as an end-user) several weeks ago. I wanted to see the list of riders in the teams of the upcoming Tour de France (the most popular cycling race that takes place every year in France). So I went to an internet site and could see a list of all the teams. At the left of each team's name was a button that allows to zoom in the team and see the list of riders. I clicked the button but nothing happened. I could see however that the space between the team name I clicked and the following team name increased a bit. So my guess was that the riders were not yet defined. The server software probably returned an empty list which was then rendered as an empty table with some paddings or margins. That's why I saw the page moving a little bit but no data were displayed. What I would have preferred of course was a clear message that the riders have not yet been defined.

In both worlds, it is of course easy to display an appropriate message.

In the avoid-null world, we improve the code as follows:

String customerID = "123";
List<ICustomerOrder> result = getOrdersByCustomer ( customerID );
if ( ! result.isEmpty() ) {
   // code to display orders ...
} else {
   System.out.println ( "No orders yet for customer " + customerID + "." );
}

In the love-null world, the code becomes:

String customerID = "123";
List<ICustomerOrder> result = getOrdersByCustomer ( customerID );
if ( result != null ) {
   // code to display orders ...
} else {
   System.out.println ( "No orders yet for customer " + customerID + "." );
}

As we can see, the only difference in both versions is the check for 'no orders':

if ( ! result.isEmpty() ) {

versus:

if ( result != null ) {

This was just a simple example, but there is already a very important lesson to take away:

The case 'no data' is semantically different from the case 'one or more elements have been found'.

This is a crucial point, although there is nothing to be astonished about. In real life, we are very well used to make this difference all the time and react appropriately, for example:

  • The case 'the classroom is empty' is very different from 'there are one or more students in the classroom'. In the first case, there is no need for a teacher to teach a lesson, the windows should be closed, the lights turned off, etc.

  • The case 'there are no customer complaints' is very different from 'some customers report a software problem'. In the first case, we can relax, surf the net, call mum, whatever. In the second case we can't.

  • etc, etc.

There are of course exceptions. Sometimes, we don't need to differentiate and both cases can be treated in the same way. But these are exceptions and they occur rarely. The point is that in the large majority of situations, it is important to react differently.

The obvious conclusion for software developers is this: We should always be careful, think about both cases and answer the question: Do I need to check for 'no data' and do something else if there are 'no data'.

This distinction can of course very well be done in both worlds. In the avoid-null world, we simply check if the list is empty. In the love-null world, we check for null. In both worlds, we can write perfectly valid and reliable code that makes our users happy. So that is not the problem. The real problem is that (in both worlds) we often forget to make this important distinction - we forget to check if the result is an empty list or we forget to check if the result is null.

So, what we have to find out now is this: What are the possible consequences in both worlds of forgetting to check for 'no data'.

In the above example, we just had a no-catastrophe-but-should-be-fixed situation.

The consequences can also be dramatic, as we'll see.

Aggregate Values

Imagine a real estate company that sells houses. The price of a house is calculated by adding different components that make up the total price. For example:

land: 100,000
house: 200,000
administrative costs: 2,000
total price: 302,000

To model this, we could define the following interface:

public interface IHouse {

   public int getID();
   // more attributes not shown here

   public Map<String, Double> getPriceComponents();
   public Double computeTotalPrice();
}
[Note] Note
In a real world application, it would be better to use a Money type instead of Double.

Suppose we live in the avoid-null world. Then getPriceComponents() never returns null.

The implementation of computeTotalPrice() looks like this:

public Double computeTotalPrice() {

   Double result = 0.0;
   for ( Double component : getPriceComponents().values() ) {
      result = result + component;
   }

   return result;
}

Now suppose that for a given house, the price components are not yet defined in the database. We don't know the price yet.

Then getPriceComponents() returns an empty list.

And computeTotalPrice() returns 0.

And this is potentially harmful.

Why?

Because we assume that the house's selling price is 0 although the price components are not defined yet.

This is the same as directly entering 0 as price in a similar application that has just a single price field (no price components).

In a real life shop, this would be like displaying 0 as price for a product whose price is not yet defined. What should be displayed is no price at all or a message such as "please ask for price".

We have now the same situation as described in Why We Should Love 'null' under section 'Using Zero Instead of Null'. With potentially evil consequences, such as displaying 0 as price for houses on the company's web site and allowing visitors to get houses for free.

House for free

Selling price: 0.00

(picture by martinlabar license: CC BY-NC 2.0)

Yes, this is a bit exaggerated, but exaggerated examples sometimes help to make a point. Anyway, imagine a company that sells thousands of low price products and deliberately offers some of them for free (example: some Amazon Kindle books are free). Then there is a real chance that nobody in the company spots the error and customers get non-free products for free. Mistakes like this do happen in real life.

We can fix the bug, of course. For example, we can return null in computeTotalPrice() if getPriceComponents() returns an empty list:

public Double computeTotalPrice() {

   if ( getPriceComponents().isEmpty() ) return null; // bug fixed

   // rest of code ...
}

But this solution introduces an inconsistency because now we return null although we live in the avoid-null world. Some programmers actually like this solution because in the forums they tell us: "In case of collections, I never return null (I return an empty collection), but in other cases I might decide to return null."

No doubt, this solution could be acceptable because it allows us to write correct code and eliminates the risk of displaying 0 as price. Still, it works only if we actually check for 'no data'.

Let us now move to the love-null world, which means that getPriceComponents() returns null if the components are not yet defined.

Suppose we write the same code as before for computeTotalPrice():

public Double computeTotalPrice() {

   Double result = 0.0;
   for ( Double component : getPriceComponents().values() ) {
      result = result + component;
   }

   return result;
}

Now we have a bug too, because an exception is thrown in the for statement if getPriceComponents() returns null.

However, there are three significant differences between this bug and the one we encountered in the avoid-null world:

  • This bug is more likely to be discovered early.

    The first time the code is run with getPriceComponents() returning null during development or testing, a NullPointerException is thrown and the programmer/tester gets aware of the bug immediately.

    On the other hand, a bug that produces a wrong value but doesn't cause an application crash is less likely to be discovered before shipping the software.

  • The outcome of this bug is less severe.

    Even if the bug escapes the eyes of the developers/testers and is shipped to the customer, what happens then is an application crash in production mode, caused by a NullPointerException. This is not nice at all, but obviously much less painful than silently continuing execution with wrong data and risking severe consequences, such as giving non-free products for free.

    Continuing execution with wrong data is among the worst things a software can do. Imagine a doctor in a hospital who decides how to treat a patient, based on wrong data delivered by software.

  • This kind of bug is easier to debug.

    Bugs that cause NullPointerExceptions are usually easy to debug because the cause and effect are short-distanced in space (i.e. location in source code) and time.

    For example, in our case the statement...

    for ( Double component : getPriceComponents().values() ) {

    ... caused a NullPointerException.

    The exception is thrown in the method that contains the bug and it is thrown immediately when the buggy statement is executed. Hence we can spot the bug immediately and we can fix it easily.

    On the other hand, software that computes wrong results and silently continues execution until a problem is detected much later is more difficult and time-consuming to debug. Just imagine a worst case scenario of an application that computes wrong data and stores them in a database which is read by another application. Although the bug is in application 1, the malfunction will appear in application 2!

It is trivial to fix the bug in computeTotalPrice(). We just have to return null if getPriceComponents() is null:

public Double computeTotalPrice() {

   if ( getPriceComponents() == null ) return null; // bug fixed

   Double result = 0.0;
   for ( Double component : getPriceComponents().values() ) {
      result = result + component;
   }
        
   return result;
}

This solves the problem.

Now, if we have 'no data' about the price components, then we also have 'no data' about the total price - our data are consistent.

And if anywhere else in the source code we forget to check if computeTotalPrice() returns null then another null pointer error will be thrown.

The risk for displaying 0 and giving products for free doesn't exist.

[Note] Note

If we use Java 8, we can also use the java.util.stream.Stream class to compute the sum in a 'functional' way, like this:

public Double computeTotalPrice() {
   return getPriceComponents().values().stream().mapToDouble(x -> x).sum();
}

However, this wouldn't change anything in the above discussion. The behaviour would be exactly the same.

Now let's go a step further and suppose we have the luxury of using a programming language that provides compile-time null-safety.

In short, this means:

  • All object references are non-nullable by default. If null is allowed, then it must be explicitly stated in the source code, for example by using a nullable keyword, or by suffixing the type name with a ?.

  • The compiler requires all nullable references to be checked for null before an operation can be performed on them.

Interface IHouse would be defined like this (note that the code below is invalid Java code, because Java doesn't provide null-safety):

public interface IHouse {

   public int getID();

   // more attributes not shown here

   public nullable Map<String, Double> getPriceComponents();
   public nullable Double computeTotalPrice();
}

As we can see, the nullable keyword makes it clear that getPriceComponents() and computeTotalPrice() can return null. This is an absolutely essential information - not only for the compiler, but also for human readers of the API as well as for additional tools. We don't have to wonder anymore if the methods might return null. Now we know they might, and we have to consider this.

But the really exciting thing is that the compiler will now nag if we forget to check for null. The following code generates a compile-time error, because getPriceComponents() could be null and we don't check that:

public Double computeTotalPrice() {

   Double result = 0.0;
   for ( Double component : getPriceComponents().values() ) {
      result = result + component;
   }
        
   return result;
}

Null-safety helps us to write more reliable code more quickly because the compiler reminds us to check for null if we forget it (and that happens quite often in practice). We have to fix the code, like this:

public Double computeTotalPrice() {

   if ( getPriceComponents() == null ) return null;

   Double result = 0.0;
   for ( Double component : getPriceComponents().values() ) {
      result = result + component;
   }
        
   return result;
}
[Note] Note
For more information about null-safety and an overview of languages that support null-safety, please refer to the previous article Why We Should Love 'null', section 'So, Is There A Better Solution?'.

Let us go back to the avoid-null world and look again at the implementation of computeTotalPrice() that uses a stream (introduced in Java 8):

public Double computeTotalPrice() {
   return getPriceComponents().values().stream().mapToDouble(x -> x).sum();
}

We saw before that it would be less error-prone if computeTotalPrice() returned null in case of an empty list. An interesting question arises: Wouldn't it be better, then, if method sum() in java.util.stream.IntStream (which we use in the above code) returned null in case of an empty list, instead of returning 0?

No! That can't be done, because an empty list can also mean 'there is indeed a list and we know that it is empty', This is different from saying 'we have no data about the list'. In the first case, the sum is indeed zero, but in the second case we don't know the sum. However, in the avoid-null world, an empty list would be used in both cases. So, if we use sum() with an empty list, we have to consider the meaning of the empty list and then decide if the value zero is acceptable. We have to be careful.

Ok, here is another question:

Method min() in java.util.stream.IntStream can be used to get the minimum value in a list of integers. What should this method return if the stream is fed from an empty list? Should it also return 0 (like sum()), or should it return the lowest negative value of a 32 bits signed integer, or should it return null.

This time, there is no other choice than to return null, because even if the empty list means 'there is indeed a list and we know that it is empty', it doesn't make sense to compute a minimum. If we look at the API documentation of min() we can see that this is indeed the result returned. However, min() doesn't return null, but an OptionalInt, because this is the pattern used in Java 8 for methods that might return with 'no data'. (Note: For a discussion of the Optional pattern (instead of returning null), please refer to the previous article Why We Should Love 'null', section 'The Optional/Maybe Pattern'.)

As we can see, there's a good amount of caution necessary.

Compare this to what we have to think about in the love-null world. If a list is null then its sum, minimum, maximum, average, and everything else is simple also just null. Simple!

A Buggy Voting Application

Here is a last, slightly more complex example of what can happen if we use empty lists to denote 'no data'.

Imagine a voting application used to select a winner among 3 candidates. Scores for each candidate are collected in five regions. The winner is the candidate with the highest average score of the five regions.

Suppose that the following function is used in the application to sum up the voters' individual scores for a given candidate in a given region:

public static Integer computeTotalScore ( List<Integer> scoresOfVoters ) {
   Integer totalScore = 0;
   for ( Integer score : scoresOfVoters ) {
      totalScore = totalScore + score;
   }
   return totalScore;
}
[Note] Note

As noted already, we could also use a stream (available in Java version 8) to compute the total:

public static Integer computeTotalScore ( List<Integer> scoresOfVoters ) {
   return scoresOfVoters.stream().mapToInt(x -> x).sum();
}

However, whether we use a stream or not doesn't change anything in the following discussion.

Now suppose that all scores have been collected and entered into the database, except the scores for candidate 2 in region 3.

If we live in the avoid-null world, then computeTotalScore() is called with an empty list as input and returns 0.

The table below shows an example of the data hold somewhere in the heap:

  Candidate 1 Candidate 2 Candidate 3
Average 370.4 422.8 478.8
Region 1 251 154 485
Region 2 548 652 145
Region 3 412 0 965
Region 4 496 954 415
Region 5 145 354 384

Note the value 0 for candidate 2 in region 3.

The consequence is severe! Our voting application might elect the wrong candidate as winner. It reports candidate 3 as winner, although in reality candidate 2 might actually be the winner. If the actual score of candidate 2 in region 3 is below 280, then we are lucky - candidate 3 is indeed the winner. If the missing score is 280, then there is a tie between candidate 2 and 3. And the real winner would be candidate 2 if the missing score is greater than 280. (Note: I used a spreadsheet to compute the values.)

[Note] Note
We could also imagine that the scores in the table are values between -100 and +100. Then 0 would be a perfectly valid value in the table and the chance of somebody spotting the error would be diminished.
Winner

And the winner is ... number 3

(picture by foilman license: CC BY-SA 2.0))

This can't happen if we love null. In case of 'no data yet for candidate 2 in region 3' computeTotalScore() immediately throws a NullPointerException. This is embarrassing if it happens in production mode, but the unacceptable risk of electing the wrong candidate doesn't exist.

Space and Time Considerations

This is a no-brainer.

null is always cheap in terms of space and time.

On the other hand, it takes time to create empty lists and it takes space to store them - in memory, on a local disk, on a remote computer, or wherever. And after they are no more used, the memory must be reclaimed (manually or automatically by a garbage collector).

To mitigate this problem, we should always use immutable and shared empty lists (in case we can't return null, for whatever reason). In Java, we should use the Collections.emptySet(), Collections.emptyList() or Collections.emptyMap() methods that return immutable and shared objects for generic collections. Here is an example of how to use them:

public static List<String> getStringList() {

   List<String> result;
// if ( there_are_data ) {
      result = new ArrayList<String>();
      result.add ( "foo" );
      result = Collections.unmodifiableList ( result );
// } else {
      result = Collections.<String>emptyList();
// }

   return result;
}

Checking for 'no data' is also more efficient if we use null. A test like:

if ( list == null )

is executed faster than:

if ( list.isEmpty() )
[Note] Note
Just to get an idea, I made a quick and dirty test and the result in my environment was that if ( list == null ) was about 3 times faster. The performance difference can of course vary largely, depending on many factors, such as the compiler, JVM, hardware architecture, etc.

In any case, the conclusion is obvious:

When it comes to time and space, null wins. Always.

API Considerations

Another interesting aspect to consider in both worlds is the API differences between collections returned by functions.

In the following discussion, we suppose that:

  • In the avoid-null world:

    • We return an immutable list with 0 or more elements.

    • If there are no data, we return an empty list.

  • In the love-null world:

    • We return an immutable list with 1 or more elements.

    • If there are no data, we return null.

Let us consider the following simplified interface:

public interface IImmutableList<E> {

   // returns true if the list is empty
   boolean isEmpty();
   
   // returns the number of elements in the list
   int size();
   
   // get the first element in the list
   E first();
   
   // get the last element in the list
   E last();
   
   // get an iterator to loop over all elements
   Iterator<E> iterator();
   
   // more features
   // ...
}

The table below shows the API differences between a list that is allowed to be empty and a list that always contains at least one element.

Method Emptyable list
(0 or more elements)
Non-emptyable list
(1 or more elements)
isEmpty() is useful doesn't make sense
should be removed
size() returns 0 or a positive integer value returns a positive integer value
(never returns 0)
first()
last()
throws an exception if the lists is empty never throws an exception
iterator() ok, but doesn't make sense if the list is empty ok

What we can clearly see is that the non-emptyable list has a simpler API and is less error-prone:

  • isEmpty() can be discarded. We never have to write something like:

    if ( customersFound != null && ! customersFound.isEmpty() ) {
       // ...
    }
  • size() never returns 0. This is an advantage because, as we all know, 0 is a very special value in mathematics with unique properties. We have to be careful if it appears in our application, because it can lead to subtle bugs - the most infamous one being the division by zero.

    For example, a 'division by zero' error occurs in the following code if the input is an empty list, because list.size() returns 0:

    public static int computeAverage ( List<Integer> list ) {
       int sum = list.stream().mapToInt(x -> x).sum();
       return sum / list.size();
    }
    [Note] Note
    It would be better to declare the return type of size() as 'unsigned positive integer, excluding zero', because that would increase compile-time type safety. Some language provide this type, but Java doesn't.
  • There is no risk for first() and last() to throw an exception because the list is never empty.

In short:

The necessity to represent a list with no elements (i.e. an empty list) adds complexity and makes the list more error-prone.

Moreover, it is interesting to note that many (if not most) operations just don't make sense in case of an empty list. Some operations don't hurt when they are executed, some of them don't return any meaningful value, and others might throw an exception. For example, it doesn't make sense to search for an element in an empty list, it doesn't make sense to remove elements or to sort them. One might argue that it doesn't hurt to loop over an empty list or to 'remove all elements' from an empty list. But, as we've seen already, it is better to check for 'no data' in the code and think about what it means in the current context to have 'no data', and then react appropriately. Also, executing operations that calculate aggregate values (sum, average, minimum, maximum, etc) and return non-null values for empty lists are error prone, as we saw already in a previous section.

These problems all evaporate if we return immutable, non-empty lists, or null to denote 'no data'.

Does this mean we should never return mutable or empty collections in the love-null world?

No!

It is a well known fact that we should always favor immutable objects (including immutable collections) over mutable ones. Immutable objects have no state transitions, they can be freely shared in parallel-computing environments and they are less error-prone.

However, sometimes (rarely) the role of a function is to return a mutable collection that can be completed or updated after the function returns it.

Moreover, sometimes (rarely) it makes sense to return an empty collection (or null) in the love-null world.

Consider a function that returns a box of cookies. If there is no box, the function returns null. If there is a box, but it is empty, the function returns an empty collection. Otherwise it returns a non-empty collection. If cookies can be eaten after the function returns, the collection should be mutable, otherwise it should be immutable.

In short: In the love-null world, the type of collection returned by functions is typically:

  • immutable and non-emptyable most of the time
  • sometimes (rarely) mutable
  • sometimes (rarely) emptyable

Summary and Conclusions

Here is a summary of the most important points to remember:

Returning null instead of empty collections might result in better performance, because empty lists need time to be created and discarded, and they need space to be stored. To minimize this inconvenience, we should return shared immutable empty collections.

If used judiciously, the 'return an empty list' approach as well as the 'return null' approach both allow us to write correct and reliable code.

Problems occur with both approaches when we forget to consider the different semantics of 'no data' and '1 or more elements' (i.e. we forget to check for an empty list or we forget to check for null).

The possible consequences of forgetting to differentiate are not the same with both approaches:

  • If we apply the 'return an empty collection' approach:

    • The outcome is unpredictable and can vary from totally harmless to extremely harmful.

    • In many cases, a wrong value is computed and program execution continues without an error message. Continuing silently with wrong values can be disastrous.

  • If we apply the 'return null' approach:

    • Most of the time, the outcome is predictable: a null pointer error occurs and the application crashes (unless the null pointer error is caught and handled appropriately).

Both outcomes are undesirable. But an application crash due to a null pointer error is (most of the time) less terrible than a program that silently continues and delivers wrong results or leads to other unacceptable outcomes or catastrophes. The 'return null' approach clearly supports the important Fail-fast! principle. This is especially important and totally harmless during development mode and helps to write more reliable code in less time.

In a nutshell: The 'return null' approach:

  • leads to faster program execution (might be unnoticeable)
  • uses less memory (might be negligible)
  • can use simpler and less error-prone collections
  • most importantly: reduces the risk of terrible outcomes due to a bug

The final conclusion is obvious:

If we have the choice, we should use the 'return null' approach.

[Note] Note
Sometimes, we don't have the choice. For example, if we work in an environment where 'return an empty collection and not null' is the rule and applied by all members of the team, then we should do the same, even if we are convinced that returning null is better. Swimming against the tide creates inconsistencies and leads to other evil problems.

The risk of forgetting to check for 'no data' is completely eliminated if we 'return null' and use a programming language with compile-time null-safety built in. In such an environment, all bugs described in this article are detected at compile-time and can't occur at runtime. This is the ideal solution. If we have the choice we should always opt for it.

Note to readers: Comments are very welcome, especially if this article misses additional points to consider, for example other advantages/disadvantages of both approaches.

In the next part of this article series we will look at empty lists and nulls in real life. Do they exist? How are they handled? You can look forward for some lightweight, but illuminating entertainment.

Links to Related Articles

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here