I don't know any language not having
flaws/limitations/imperfections/missing-features, so here are merd's.
The items below can range from imperfection to flaws, depending on the item,
but also (and quite importantly) on what people think is right or wrong.
Variable declaration
merd has chosen the Python way of declaring variables. It's expressive, but it
doesn't scale well in very nested constructs where you can't know wether a
assignment is a side-effect or a declaration.
! The scope of variables is still an open issue !
One element tuple
merd uses "((a))" for 1-uple.
See the explaination of this trade-off
Using a tuple for a function call
add(x,y) = x + y
t = (1, 2)
s = add(t)
Seems quite ugly. Alas, disallowing "add(t)" and forcing to use
"add(*t)" a la Python/Ruby [1] implies the following
for higher-order functions:
apply(f, x) = f(x)
apply'(f, x) = f(*x)
s = apply(add, t) #=> error
s' = apply'(add, t) #=> ok
Which is detrimental to functional programming [2]
List containing a tuple
- list containing 1 and 2:
l1 = (1,2) has type List(1|2), or
l1 = [1,2] has type List(1|2)
- list containing the tuple "1,2":
l2 = ((1,2)) has type ((1,2))
l2 = [((1,2))] has type List(1,2)
- OCaml avoid this problem by using ";" for separating list elements:
l1 is "[1;2]" and l2 is "[1,2]"
- in Haskell and Python, l1 is "[1,2]" and l2 is "[(1,2)]"
Assignment doesn't return any value
This means you can't write if ((i = 0)) ... as you can do in C.
Control structures are multi-operators
This means there must be exactly one argument between each operator.
For example "while a do b" is "multiple_while_do(a, b)".
Since control structures are no special construct, you can't have something like:
- C's "if (cond) do_something" (note the special mandatory parenthesing around the condition)
- Ruby's "if cond ; do_something end"
Values in strings
"foo{val}bar" is "foo" + val.to_string + "bar". It means
that it doesn't enforce that val is a string.
Complexity
The flexibility of the type system allows a nice expressivity together with
static typing. The penalty is of course the complexity of the types, and
complex type error messages.
Compile-time cost
The algorithm for infering/checking types is time costly.
Run-time cost
The ability to multiple dispatch implies some computation to find out the
right function to call. The case is worse than most languages having runtime
dispatch because the types are anonymous, a value belonging to a potentially
infinite lattice of types.
Expressivity "restrictions"
- return values must be explictly ignored
- numbers, strings... are not boolean values (contrary to C/C++/Python/Perl/Ruby [3])
Notes
[1]
Using prefix "*" would conflict with multiplication.
[2]
Here is the Python version:
def apply(f,x): return f(x)
def apply2(f,x): return f(*x)
def add(x,y): return x+y
apply (add, (4,5)) #=> TypeError: add() takes exactly 2 arguments (1 given)
apply2(add, (4,5))
[3]
What is true depends from one language to another:
0 | "" |
false | false | Perl, Python, JavaScript, PHP |
true | true | Ruby, Common Lisp, Scheme, Dylan |
false | true | C |
false | error | Tcl |
Pixel
This document is licensed under GFDL (GNU Free Documentation License).
Release: $Id: flaws.html,v 1.9 2002/05/17 15:22:56 pixel_ Exp $