RU beehive logo ITEC dept promo banner
ITEC 380
2018fall
ibarland

Why study programming languages?

You can never understand one language until you understand at least two.
John Searle
The limits of my language are the limits of my world.
—Ludwig Wittgenstein

Why study programming languages?

Languages steer programmer’s decisions

Java encourages choosing bad integer arithmetic

Java, python encourage bad rational arithmetic

Consider: 7 · 25 ÷ 25.
Also: 2.5 + x - x + 2.5.

Java, python, racket encourage bad irrational arithmetic

What is √2 · √2 ? (Give the racket expression.)
In sage:

Note a different language issue, in that third example: we provided the argument “n(, digits=50)”, rather than just passing 50 as the second argument. That’s “keyword arguments”; why/when might it be helpful? (It turns out python1 allows this, and sage is built on python.)

Why the difference?

You've probably guessed that the different behaviors above stem from how the data is represented internally. Java (and many languages) represent primitive ints and floats using a fixed 32-bits (and using 64-bits for long and double). If a number can’t fit in 32-bits, it can’t be represented by that type.

For arbitrary-precision integers, you can keep track of a list-of-digits2 This is what racket and python do by default, and what Java uses java.math.BigInteger for.

In the same vein, representing rational numbers exactly is straightforward, if you use a struct with two fields (the numerator and denominator).

(In dynamically-typed languages: the machine representation might include a tag, which requires a few bits. For example, a 32-bit quantity starting with the bits 101 might happen to let the language know that this quantity is the start of a string. For common types, a shorter tag might be used; since int is a very common type, a single leading bit of 0 might indicate a small-integer (one that fits in the remaining bits), and that lets the language-implementation use existing integer-arithmetic-hardware for that value!)

video (20m02s)

Java encourages you to use arrays (even when lists are better)

Suppose you want to keep list of temperatures on recent days (in Celcius, of course).

    List<Integer> nums = new ArrayList<Integer>();
    nums.add(22);
    nums.add(17);
    nums.add(24);
    nums.add(30);
    nums.add(5);
    
    if (nums.contains(n)) {
      ...
      }
  
Oh my goodness!

What if you want to use an array? Java makes that much easier for you:

  Integer[] nums2 = {22, 17, 24, 30, 5};
So if you want to sort a bunch of items, it’s concise to use an array, and verbose to use a List — Java is encouraging the programmer to use an array, even if a List is more appropriate.

It’s worth mentioning that although Arrays are easy to declare, iterate over, and statically-initalize in Java, they're also a bit underdone: there are many useful functions for arrays that Java didn’t include (not even when they added the utility-class java.util.Arrays); a contains method is one of them (!). You can download a third-party libraries (like guava or apache-commons (written since others were fed up with this shortcoming), or you can often convert the array to a list, and then use the standard java.lang.Collections methods:

  Integer[] nums2 = {22, 17, 24, 30, 5};
  List<Integer> nums1 = java.util.Arrays.asList( nums2 );

Recent versions of Java finally allow even more succinct phrasings, which finally rival the conciseness of their array-syntax using mere method-calls:

  List<Integer> nums1 = java.util.Arrays.asList( new Integer[] {22, 17, 24, 30, 5} ); // creates an *immutable* list!

  // In Java 10:
  var nums1 = java.util.List.of( 22, 17, 24, 30, 5 );  // creates an *immutable* list!

Warning:

Java's asList method is documented as “Returns a fixed-size list...”. If you take its result and call (say) the .add method, it throws an UnsupportedOperationException — This is unintuitive behavior! When a method says it returns a List, the standard expectation is that it returns an object which supports the methods of interface List — that's what (abstract) types are all about! A developer shouldn't have to memorize which of the umpteen java.util.List methods create Lists that don't actually support all the List methods.

If they had named the method asImmutableList, it would make sense. Or if they just had the method return an actual List (and copy the backing array), it would make sense. They decided to favor both runtime-performance and short names, at the expense of violating both the Principle of Least Surprise and the good-O.O. practice of avoiding UnsupportedOperationExceptions. (Also, the designers might have made a interface ImmutableList, to avoid a plethora of UnsupportedOperationExceptions.)

Lisp encourages you to use lists (even where arrays may be better)

While Java priviliges strings and arrays with particularly simple syntax and rules, Lisp priviliges lists (in fact, its name stems from “List Processing”). Instead of constructing (list 320 'ibarland 2018 'fall), one can write '(320 ibarland 2018 fall). This gets more convenient when you need lists-of-lists: instead of

(list (list 320 'ibarland 2018 'fall)
      (list 320 'nokie 2018 'fall)
      (list 380 'ibarland 2017 'fall)
      (list 220 'jchase 2018 'spring))
       
you can use quote (') to write
'((320 ibarland 2018 fall)
  (320 nokie 2018 fall)
  (380 ibarland 2017 fall)
  (220 jchase 2018 spring))
       
(And we won't even think about how to represent this data in idiomatic Java; it involves a new classes and enumerated types and constructor calls, in addition to the list-creation itself.)

Furthermore: Lisp families have, in addition to quote, a back-quote (`) which lets you do even more!

Note that if using arrays (“vectors” in Lisp), there is a “long” constructor (using (vector 4 "hi" 5) analagous to (list 4 "hi" 5)), but there is also a shorthand (using #'[4 "hi" 5] analagous to '(4 "hi" 5)). BUT: there are so many built-in functions for handling lists, and so many libraries which uses lists as arguments and/or return-types, that in a LISP language I am sorely tempted to use lists even if I acknowledge that vectors are a more appropriate data-type3. Arguably the push to use this approach is not coming from the language by itself, but rather from its 3rd-party libraries. However, that is still a real force at work in real languages.

python

Special mention goes to python, for their convenient and mnemonic shorthand-syntax for some particularly-common (and useful) data types:

And a reminder that by seeing what other languages make easy or difficult, you gain the ability to see what your "primary" language is making easy or difficult — “You can never understand one language until you understand at least two.”.


1 Keyword arguments are allowed in racket, but they aren’t automatic like they are in python. On the other hand, keywords are values, so you can pass/return keywords from functions.      
2 Where each individual “digit” is perhaps a 32-bit quantity, or so.      
3 Sure, there are functions which will convert a list to a vector and vice versa. However, if I need to constantly convert back and forth, I still have the tempation to just stick with using lists throughout.      

logo for creative commons by-attribution license
This page licensed CC-BY 4.0 Ian Barland
Page last generated
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Rendered by Racket.