"everything is a function" -- this is confused. Spad has functional
interfaces, meaning that you can not directly get domain data
(in Java speak all member variables are private and you can
get them only if there is appropriate accessor function). Spad
uses functional notation of other operations:
a(b)
may be:
- function a applied to b
- element number b of array a
- element number b on list a
- field b of record a
- something different if appropriate 'apply' operation is defined
but application is not always defined, for example '1(2)' does
not "work".
Concerning OO, Spad gives you some OO capabilities, but they are
different than in other languages. You may use Spad categories
like Java interfaces and domains like classes, but while
inheritance for categories works like in Java, inheritance for
domains is different (in C++ speak all methods defined in a
domain are static).
Spad distinctive feature is its type system. Spad is "statically
typed" meaning that compiler knows how to compute "static" type
for each quantity. I put "static" in quotes because in Spad
types are actually computed at runtime (in some cases Spad
compiler can determine type already during compilation, but
frequently it can not). Spad is different from dynamically
typed languanges which bundle type information with actual
data -- in Spad type information is separate. This means that
Spad compiler has a lot of opportunities to omit computations
on types. Spad approach is also different than typical OO
approcach: in Java interfce is statically known but at
runtime you may have any object which satisfies given interface.
So in practice Jave also have to bundle object type (class) with
data. In Spad OO type inheritance is is available ony for
categories (types of types), but not for normal data. So for
normal data type computed by the compiler exactly agrees with
actual type of data.
I should mention here that many of Spad types are parametrised,
for each tuple of parameteres you get distinct type. Spad
types may be passed as arguments to functions and returned
as values -- this in principle gives quite a lot of possibilites
to do computations on types. Let me add that types computed
at runtime pose a significant challenge for the compiler,
especially that Spad has type-based overloading --
there is a risk that compiler will be forced the generate
very inefficient code. Spad solves most of this problem
putting some extra restricions: you are not allowed to do
general runtime computation on categories, all categories
(except for exact values of parameters) must be known to the
compiler at compile time. Moreover, for resolving overloading
Spad does not use actual type (which is known only at runtime),
but only category of the type. This means that in most cases
compiler is able to resolve overloading at compile time
(if it can not resolve some case the compiler simply uses
first match, or signals error if it has insufficient information
to find any mutch).
You ask "So how does spad match an instance of a domain to the function
definition?". This is not well-posed question. You probably
want to know how Spad decides which function to call. This is
two stage process. The first stage is overload resolution at
compile time. In given call place there may be several (or none)
visible definitions for given function. Each definition comes
from some domain or package. Recall that domains and package
are computed at runtine: the Spad compiler knows how to compute
apropriate domains and for each of them knows associated category.
Note that category is known at compile time and gives list of
functions available in the domain (the domain may export more
functions, but the compiler only uses compile-time information
about available functions). Given list of available functions
Spad compile tries each in turn to see if types of arguments
agree with function declaration and if the result type is acceptable.
Note that Spad allows you to have multiple functions with the
same argument types, which differ only in the result type, so
the expected result type affects choice and complicates the
resolution process. Let me say that it may be hard for
programmer to predict which function will be used by the
compiler, if that is a problem the programmer may explitely
specify types, like:
(foo(x1@Type1, x2@Type2)$Type3)@Type4
which means that the compiler will check that x1 is of type Type1,
x2 is of type Type2 and then search domain (or package) Type4 for
function foo which takes arguments of types Type1 and Type2 and
returns value of type Type3. Let me add that code for resolving
overloading in the compiler is not very large, but in a sense it
is most complicated part of Spad compiler. Actually, the problem
with overloading is that it is impossible to do "right thing"
with reasonable efficiency, so the compiler takes shortcuts
which make hard to describe what the compiler is actually doing.
Now, you may think that overload resolution chooses concrete
function to call, but in fact there is more to this. First,
list of available fuctions is known at compile-time, but the
domain may be only known at runctime -- this is quite similar
to Java where interface in statically known, but actually
object class in known only at runtime. Second, the function
in not necessarily implemented in given domain -- it may be
inherited. This requires runtime search. While inheritance
have similarity to typical OO languages, there are significant
differences.
--
Waldek Hebisch
heb...@math.uni.wroc.pl