Constant interface

Last updated

In the Java programming language, the constant interface pattern describes the use of an interface solely to define constants, and having classes implement that interface in order to achieve convenient syntactic access to those constants. However, since constants are very often merely an implementation detail, and the interfaces implemented by a class are part of its exported API, this practice amounts to putting implementations details into the API, which was considered inappropriate by, e.g., Java designer Joshua Bloch. [1] In general, collecting system constants into classes independent of behaviour might create a poor object-oriented design because it is often a sign of low cohesion. For these reasons, constant interfaces may be considered an anti-pattern.

Contents

Use of this pattern has a few other downsides:[ original research? ]

  1. It pollutes the class namespace with read-only variables that may not be of use.
  2. Contrary to the compile-time tactical utility of implementing a constant interface, the incidental run-time artifacts have little practical purpose (cf. marker interfaces which also have no methods but are useful at run-time).
  3. If binary code compatibility is required in future releases, the constant interface must remain forever an interface (it cannot be converted into a class), even though it has not been used as an interface in the conventional sense.
  4. Without an IDE that resolves where the constant are coming from, tracking it back to its containing class or interface can be time consuming.
  5. An instance of the interface is syntactically no more useful than the interface name itself (since it has no methods).
  6. Unless a developer checks any implemented interfaces when adding a constant to a class, or does so but makes a typo in the name of the added constant, the value of a constant can be silently changed. Consider Example 2 below.

Note that the Java libraries use constant interface pattern themselves. For example, the SwingConstants interface [2] was released in 1998, [3] and then it was a reasonable choice.

Example 1

publicinterfaceConstants{doublePI=3.14159;doublePLANCK_CONSTANT=6.62606896e-34;}publicclassCalculationsimplementsConstants{publicdoublegetReducedPlanckConstant(){returnPLANCK_CONSTANT/(2*PI);}}

Example 2

publicinterfaceConstants{publicstaticfinalintCONSTANT=1;}publicclassClass1implementsConstants{publicstaticfinalintCONSTANT=2;// *publicstaticvoidmain(Stringargs[])throwsException{System.out.println(CONSTANT);}}

Before the line marked with an asterisk is added, running Class1 prints 1. After adding the line, Class1 prints 2. Both versions compile without warnings or errors.

Alternatives

Many of the pitfalls of the anti-pattern can be avoided by converting the constant interface to a class with static attributes:

publicfinalclassConstants{privateConstants(){// restrict instantiation}publicstaticfinaldoublePI=3.14159;publicstaticfinaldoublePLANCK_CONSTANT=6.62606896e-34;}

Since Java 5, one can use static import [4] to be able to use the constants without the Constants qualifier:

import staticConstants.PLANCK_CONSTANT;import staticConstants.PI;publicclassCalculations{publicdoublegetReducedPlanckConstant(){returnPLANCK_CONSTANT/(2*PI);}}

The constants can also be imported en masse by using an import static Constants.* statement. This achieves the same goals as using an interface, allowing the constants to be referenced without a qualifier.

To varying degrees, the issues listed above have now been addressed:

  1. Because static members can be imported specifically, the class namespace need not be polluted with all members of the constant interface.
  2. Run-time and compile-time semantics are more closely aligned when using static imports instead of constant interfaces.
  3. The compiled code has one fewer binary compatibility constraint (that "class Calculations implements Constants").
  4. Because static imports apply only to the current file (and not the whole class hierarchy) it is easier to discover where each static member is declared.
  5. There is less need to declare variables of the constant interface type, and it is potentially clearer that no concrete instance actually exists.

Note, however, that the changes do nothing to improve the cohesion of the Constants class nor prevent the accidental silent modification of the value of a constant, so static imports should not be considered to be a panacea.

Related Research Articles

<span class="mw-page-title-main">Dylan (programming language)</span> Multi-paradigm programming language

Dylan is a multi-paradigm programming language that includes support for functional and object-oriented programming (OOP), and is dynamic and reflective while providing a programming model designed to support generating efficient machine code, including fine-grained control over dynamic and static behaviors. It was created in the early 1990s by a group led by Apple Computer.

In computing, a namespace is a set of signs (names) that are used to identify and refer to objects of various kinds. A namespace ensures that all of a given set of objects have unique names so that they can be easily identified.

<span class="mw-page-title-main">Singleton pattern</span> Design pattern in object-oriented software development

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to a singular instance. One of the well-known "Gang of Four" design patterns, which describes how to solve recurring problems in object-oriented software, the pattern is useful when exactly one object is needed to coordinate actions across a system.

<span class="mw-page-title-main">Swing (Java)</span> Java-based GUI toolkit

Swing is a GUI widget toolkit for Java. It is part of Oracle's Java Foundation Classes (JFC) – an API for providing a graphical user interface (GUI) for Java programs.

In some programming languages, function overloading or method overloading is the ability to create multiple functions of the same name with different implementations. Calls to an overloaded function will run a specific implementation of that function appropriate to the context of the call, allowing one function call to perform different tasks depending on context.

In computer science, type safety and type soundness are the extent to which a programming language discourages or prevents type errors. Type safety is sometimes alternatively considered to be a property of facilities of a computer language; that is, some facilities are type-safe and their usage will not result in type errors, while other facilities in the same language may be type-unsafe and a program using them may encounter type errors. The behaviors classified as type errors by a given programming language are usually those that result from attempts to perform operations on values that are not of the appropriate data type, e.g., adding a string to an integer when there's no definition on how to handle this case. This classification is partly based on opinion.

This article compares two programming languages: C# with Java. While the focus of this article is mainly the languages and their features, such a comparison will necessarily also consider some features of platforms and libraries. For a more detailed comparison of the platforms, see Comparison of the Java and .NET platforms.

<span class="mw-page-title-main">Java syntax</span> Set of rules defining correctly structured program

The syntax of Java is the set of rules defining how a Java program is written and interpreted.

Managed Extensions for C++ or Managed C++ is a deprecated set of language extensions for C++, including grammatical and syntactic extensions, keywords and attributes, to bring the C++ syntax and language to the .NET Framework. These extensions were created by Microsoft to allow C++ code to be targeted to the Common Language Runtime (CLR) in the form of managed code, as well as continue to interoperate with native code.

C++/CLI is a variant of the C++ programming language, modified for Common Language Infrastructure. It has been part of Visual Studio 2005 and later, and provides interoperability with other .NET languages such as C#. Microsoft created C++/CLI to supersede Managed Extensions for C++. In December 2005, Ecma International published C++/CLI specifications as the ECMA-372 standard.

In the Java programming language, the final keyword is used in several contexts to define an entity that can only be assigned once.

An interface in the Java programming language is an abstract type that is used to declare a behavior that classes must implement. They are similar to protocols. Interfaces are declared using the interface keyword, and may only contain method signature and constant declarations. All methods of an Interface do not contain implementation as of all versions below Java 8. Starting with Java 8, default and static methods may have implementation in the interface definition. Then, in Java 9, private and private static methods were added. At present, a Java interface can have up to six different types.

<span class="mw-page-title-main">Oxygene (programming language)</span> Object Pascal-based programming language

Oxygene is a programming language developed by RemObjects Software for Microsoft's Common Language Infrastructure, the Java Platform and Cocoa. Oxygene is based on Delphi's Object Pascal, but also has influences from C#, Eiffel, Java, F# and other languages.

C# and Visual Basic .NET are the two primary languages used to program on the .NET Framework.

TypeScript is a free and open-source high-level programming language developed by Microsoft that adds static typing with optional type annotations to JavaScript. It is designed for the development of large applications and transpiles to JavaScript. Because TypeScript is a superset of JavaScript, all JavaScript programs are syntactically valid TypeScript, but they can fail to type-check for safety reasons.

In object-oriented computer programming, an extension method is a method added to an object after the original object was compiled. The modified object is often a class, a prototype or a type. Extension methods are features of some object-oriented programming languages. There is no syntactic difference between calling an extension method and calling a method declared in the type definition.

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

Static import is a feature introduced in the Java programming language that allows members which have been scoped within their container class as public static, to be used in Java code without specifying the class in which the field has been defined. This feature was introduced into the language in version 5.0.

In software engineering, the module pattern is a design pattern used to implement the concept of software modules, defined by modular programming, in a programming language with incomplete direct support for the concept.

References

  1. Bloch, Joshua, Effective Java, 2nd Edition, p. 98
  2. "SwingConstants"
  3. What is Swing?
  4. "Static Import"