|
|
The first version of this document started off to list all of the
syntactic variations.
Syntax isn't really what concerns me so much as the
larger relationships.
The strategy is to have the basic syntax
at the beginning of the list of features,
and then put the orthogonality & uniformity features farther down.
Warts & gotchas will show up as lack of orthogonality.
Warts will also be noted as limitations on basic features,
e.g. if you can't make a function in an arbitrary scope,
it's noted in functions.
This document focuses on expressive power of the language.
Listing of pitfalls (related or unrelated to expressive needs)
is not the goal of this document.
uniformities:
- lambda in any scope
- generic functions (parametric polymorphism)
- unbounded integral numbers
- compilable & packagable
My cheat sheets ignored modules/namespaces/packages. I intend to add
these to the cheat sheets.
There are some features which I'm not sure how to present
a simple example, e.g. strictness, non-strictness, laziness,
tail-recursion optimization, distinction between actions and
functions.
Being non-strict, Haskell has the potential to support the
type with 0 values, i.e. the sum of 0 types.
This strikes me as being an excellent point in favor of
non-strictness. A strict language has no concept of
returning a non-value. So for procedures which don't
return a value, Python uses the "None" type which has
one value. Since there are naturally many different
one-value types, this is a matter of convention rather than
integral to the type system. OTOH in most non-strict languages
there is a canonical type with 0 values, perfect for such
procedures.
But note that in a strict language this is an issue not for
functions but for actions, and perhaps actions that don't return
a value should have a different type.
feature | best practice | Scheme | Python | Haskell | Perl | Java | C | C++ |
names |
Any name can have any type.
One definition per name, no default value. |
|
Implicit definition of names. |
Names of values must be lower case, except for constructor functions which must be upper case. |
A name must be prefixed with $,@,%,or & depending on its type.
The prefix can select a different value, or a different
aspect of the same value. |
|
| |
comments |
end-of-line & nesting delimited |
no delimited comments |
no delimited comments |
|
no delimited comments |
no nesting |
no nesting |
no nesting |
layout |
Indentation in language's syntax.
|
indentation ignored |
|
|
indentation ignored |
indentation ignored |
indentation ignored |
indentation ignored |
syntax |
Juxtaposition is high precedence signifying tuples and/or lists.
Parentheses are for grouping, as needed and optional.
|
Parentheses are for function calls. |
no juxtaposition |
juxtaposition for function application |
no juxtaposition |
no juxtaposition |
no juxtaposition |
no juxtaposition |
equality |
Operators for equals and not-equals are
uniform across applicable types, and extensible. |
not extensible? |
? |
|
extensible? |
distinct operators for primitive vs. class types |
built-in types only |
|
sentences |
literals for true and false
infix operators for "and", "or"; prefix "not" |
|
|
|
|
|
| |
numbers |
Overflow and underflow should not happen.
Rounding & relation to hardware floating point interesting. |
floating point underflow & underflow |
floating point underflow & underflow |
floating point underflow & underflow |
floating point underflow & underflow |
integer overflow floating point underflow & underflow |
integer overflow floating point underflow & underflow |
integer overflow floating point underflow & underflow |
strings |
single- or double-quoted literals, with escapes
Unicode-capable |
not Unicode |
|
|
|
not Unicode |
not Unicode | |
lists |
Syntactic sugar exists for literal lists. |
|
|
|
|
no | no | no |
functions |
A lambda form provides function values.
Question use of currying. |
|
|
|
no |
no |
no | no |
trivialities |
How are procedures that don't return a value integrated
with those that do? |
Use a canonical value. |
None single-value type |
() single-value type |
Use a canonical value (undefined null). |
void single-value type |
void single-value type |
void single-value type |
sequences |
Lists, strings, etc. have common operators (for head, tail, concat, cons). |
no |
|
|
no |
? |
n/a |
|
actions |
An action is not a function, and should be first class. |
conflation; act() |
conflation; act() |
|
conflation; act() |
conflation; act() |
conflation; act() |
conflation; act() |
objects |
Programmer need not free memory or check pointers. |
|
|
|
|
|
no | no |
references |
Generic references with creation (new w/ initializer), read (dereference), and update (assignment) operations. |
? |
? |
|
not for most types |
not for primitive types |
Creation is awkward; manual initialization. | |
modules |
Essentially, need to indicate how chunks of a program
fit together, namewise. |
| | modules | packages | packages | #include "header.h" gives user no control | namespaces |
types |
|
|
|
type safe, capitalized type names, type variables not capitalized |
implicit conversion hell
Syntactic scalar and list contexts provide
radically different interpretations of an expression's result value. |
type safe, capitalized object types, primitive types not capitalized |
partially type safe |
partially type safe |
|
|
|