I wrote this essay for a class I'm taking this year and would like to refactor it and examine the points in greater depth at a later date.
This report aims to compare two programming languages, Ruby and Java, in the context of learning to program. It sets out to examine syntax, semantics and environments of both languages and their cognitive implications for novice programmers.
Whilst there is not a huge body of work in this area, this report builds on research that suggests that choosing a simpler programming language first can have a positive impact on student achievement (Mannila et al 2006); albeit from a cognitive perspective.
Effort has been made to explain much of the technical terminology relating to programming concepts within the report. However, there may be concepts that remain abstract for the casual reader. Unfortunately, in an effort to explore some of the more technical elements of both languages, this was unavoidable.
Ruby is a dynamic, interpreted, language that first appeared in 1995. It is often cast aside, declared inferior for simply being a scripting language (Baas 2002). This is simply not the case, Ruby has a rich object model and a full standard library that makes it an ideal candidate for solving problems across different domains. The interesting thing about Ruby is that it was designed with developer happiness in mind (Flanagan 2008).
Java is a statically-typed, compiled, language that first appeared in 1995. In the last decade it has become a popular choice of language for first-year computer science classes (Reges 2000). It is widely used in industry and replaced C++ as the vehicle for first-year computer science because of it’s modernity, object orientation, type-safety and simplicity (Reges 2002).
Visual Attention, Working Memory, Semantics and Syntax
The syntax of a programming language defines the set of rules for combining symbols in that language (Tennent 1981). Semantics, on the other hand, are the meaning attributed to the arrangement of combinations of these symbols.
Expert programmers are likely to be able to deal with demanding syntax and it is clear that many language designers have optimised for computers but not not for humans (Green 1989). Therefore, considering the syntax of a language in the context of novice programmers is incredibly important; not only because it affects their ability express themselves clearly but also because it affects their ability to understand the works of their peers.
Java and Ruby Syntax Comparison
Comparing all syntactic features of both languages is well out with the scope of this report but several examples from a single program have been chosen to reflect this author’s position that extraneous syntactical details only serve to increase the cognitive load on novice programmers.
The program being examined iterates through a range of numbers and prints them out to the console in which the program is executed. Iteration is a core construct that will be used by programmers in a variety of contexts.
Figures 1a, 1b and 1c show this program expressed in English, Java and Ruby respectively. For the purposes of this example, these programs should be considered semantically equal.
In figure 1d, we can see additional syntactical elements that are necessary for the Java program to execute. We must use parenthesis to wrap our range expression and parameters in function calls; use semicolons to isolate individual statements; and blocks of code block must be grouped together by wrapping them in curly braces.
Novice programmers will have to allocate additional working memory when constructing and conceptualising pieces of code that perform iteration in Java. Given that humans have approximately seven bits of working memory (Miller 1956) one wonders whether this is a good use of resources. This is particularly relevant when we consider these syntactical elements in the context of a larger program.
Furthermore, in this small, and admittedly trivial example, the semantic meaning of parentheses is not consistent. In the for loop we wrap a range condition but we also wrap the variable i in the arguments of the call to the print function. Without experience, chunking these high-level concepts, and their ambiguities, is unlikely to be easy for novices.
By comparison, the Ruby program is terser and the intention is not obfuscated by unnecessary syntactical details.
Elements are grouped by whitespace and not by parentheses, which prevents the information appearing cluttered. The benefit of this approach is that it results in less competing visual elements.
Similarly, the semantic content reads more like natural language, “for number in range one to one-hundred, output number.”
Visual Attention and Search
There are two basic elements to visual attention: limited processing capacity and selectivity (Desimone and Duncan 1995). Selectivity is the ability to differentiate between targets and non-targets in visual search.
Domain experts are often better equipped to make quick assessments of what information is most relevant in the context of their domain (Rayner 1998); enabling them to quickly establish targets. Conversely, novices are more likely to fixate longer on non-targets.
The biased competition model suggests that targets and non-targets compete for visual processing capacity (Desimone and Duncan 1995). The experience of domain experts allows them to make greater use of top-down processing, whilst bottom-up bias is more prevalent for novices.
This would suggest that Java would present a novice programmer with more competition between targets and non-targets. The issue here is two-fold: the cognitive load on the programmer is greater and the cognitive capacity available for high-level abstraction is reduced. Ruby doesn't suffer as much from this because, without the extraneous details, the objects become easily discriminable.
Whilst some of these selectivity problems may be mitigated with syntax highlighting (Hakala et al 2006), it seems disingenuous to students to select a language with a high signal to noise ratio that, from the outset, requires more processing to deal with low-level syntactical details.
Static and Dynamic Typing
Ruby is a dynamically typed language that relies on duck typing. This means that objects, in the context of an object-oriented program, care less about their type than they do about their public interface (Metz 2012). In concrete terms, this means that if two different types of objects respond to the same method, the same message can be passed to both of them. As a result, errors are encountered at runtime.
Conversely, Java is a statically typed language. This means that the compiler will complain if we try to pass a message to an object of a different type than we have explicitly specified.
Semantics and Syntax
The way Java handles static typing in code is that we have to repeatedly declare the different types of objects we wish to use during assignment, constructing functions and instantiating objects.
The drawback to this approach is two-fold: we add more syntactic noise to our programs, adding more competing information during visual search and we also introduce an unusual semantic style with a prominence of nouns that does not map well to the English language.
To enable polymorphic behaviour in Java, we must define an abstract base class from which related objects inherit; whereas in Ruby, we simply define the same public interface (Goldwasser and Letscher 2008). This enables novices to easily group objects by shared behaviour instead of common inheritance.
The inheritance-based approach in statically-typed languages adds an extra layer that must be understood by the programmer. Conversely, the simplicity of implementing the same interface on multiple objects to achieve the same ends is more elegant, requires less cognitive overhead and more representative of the phrase “abstract base class” because it truly is an abstraction detail that can be chunked or forgotten.
It is difficult to discuss programming languages out with the development environments that novices learn in. We must again examine some characteristics of both languages and their implications on learning and experimentation.
The Lewinian model of learning suggests that there are four stages in the process of learning. Lewin placed significant emphasis on the importance of feedback; and suggested that an impedance mismatch between observation and action lead to ineffective learning (Kolba 1984).
To place this in the context of learning to program, we must consider how easy it is to go from writing code to executing it. It is this writer’s assertion that minimising the time between writing a piece of code and executing it makes it possible to gain more concrete experience through shorter, more frequent, iterations of this model.
When programing in Java, the active experimentation stage requires some scaffolding and is more time-consuming. A special function called main() must be written inside a class, our experimentation code must then be written in an enclosing class and finally our code must be compiled and then executed.
As an example, figure 2b shows code that takes a collection of n numbers and returns a copy of that collection with each number incremented by one. This seems like a lot of code, and subsequently time, to carry out this kind of experiment.
The process of experimentation in Ruby is much different. We are allowed to load up a read evaluate print loop (REPL) called irb. In this interactive shell we have full access to the Ruby interpreter to execute both arbitrary pieces of code and entire programs.
Figure 2c shows irb being loaded within a terminal environment. The code performs the same function as the previous Java code. The real advantage here is that irb makes it possible to experiment with Ruby code without having to construct entire classes. This ability to execute arbitrary code quickly and conveniently means novices are able to evaluate plausible and implausible hypotheses with a smaller time-cost than doing so in Java.
There is no question about the robustness of the Java virtual machine, or the wealth of third-party software libraries written in Java. However, it is the position of this author that there should be more research into the cognitive implications of choosing a first programming language. Java’s verbosity, and time-consuming experimentation cycles makes it cumbersome and difficult for novices to engage in rapid experimentation activity.
Ruby, whilst not perfect, is a language that has been architected with developer happiness in mind. It offers some advantages over Java in it’s simplicity of syntax and overall flexibility. Novices can experiment, and prototype, more rapidly; gaining valuable feedback that becomes concrete experience.
This is by no means a suggestion that computer science should be “dumbed down”. On the contrary, it is about ensuring we are choosing languages that allow novices to get to the core ideas quicker. Syntactic knowledge is not transferable between programming languages but general problem solving skills are.
Baas, B, 2002. Ruby in the CS curriculum. Journal of Computing Sciences in Colleges, Vol 17(5), 95-103.
Desimone, R., Duncan, J, 1995. Neural mechanisms of selective visual attention. Annual Review of Neuroscience , Vol 18, 193–222.
Flanagan, D, 2008. The Ruby Programming Language. First Edition Edition. O'Reilly Media.
Goldwasser, M.H., Letscher, D, 2008. Teaching an object-oriented CS1 -: with Python. Proceedings of the 13th annual conference on Innovation and technology in computer science education, Vol 40(3), 42-46.
Green, T. R. G, 1989. Cognitive dimensions of notations. In A. Sutcliffe and L. Macaulay (Eds.) People and Computers V. Cambridge, UK: Cambridge University Press, 443-460.
Kolb, D.A, 1983. Experiential Learning: Experience as the Source of Learning and Development. 1 Edition. Prentice Hall.
Mannila, L., Peltomäki, M. and Salakoski, T, 2006. What about a simple language? Analyzing the difficulties in learning to program, Computer Science Education, 16:3, 211-227.
Metz, S, 2012. Practical Object-Oriented Design in Ruby: An Agile Primer (Addison- Wesley Professional Ruby Series). 1 Edition. Addison-Wesley Professional.
Miller, G.A, 1956. The magical number seven, plus or minus two: some limits on our capacity for processing information. Psychological Review, Vol 63(2), 81-97.
Reges, S, 2000. Conservatively radical Java in CS1. Proceedings of the thirty-first SIGCSE technical symposium on Computer science education, Vol 32(1), 85-89.
Reges, S, 2002. Can C# replace java in CS1 and CS2? Proceedings of the 7th annual conference on Innovation and technology in computer science education, Vol 34(3), 4-8.
Rayner, K, 1998. Eye movements in reading and information processing: 20 years of research. Psychological Bulletin. Vol 124(3), 372-422.
Tennent, R.D, 1981. Principles of Programming Languages (Prentice Hall International Series in Computing Science). Edition. Prentice Hall.