Sun Microsystems Laboratories Experimental Stuff [Fortress-interest] Some observations about the 1.0a spec

[Fortress-interest] Some observations about the 1.0a spec

Jan-Willem Maessen Janwillem.Maessen@sun.com
Wed, 03 Jan 2007 13:45:16 -0500


On Jan 3, 2007, at 7:10 AM, Mike Atkinson wrote:

> Hi,
>
> I've been reading the 1.0a spec, and have some questions,  
> observations and think I've spotted a few small errors. First some  
> things that seem to be missing, no doubt some of these are  
> deliberate and others you have not got round to adding yet.
>
>
> Missing? Closures

Fortress has first-class functions, which can be written anonymously  
using the "fn" keyword; see 13.7.  They can make use of arbitrary  
free variables occurring in their context.  I personally use them  
quite a bit.

Perhaps you have some other notion of what constitutes a closure?  If  
so, I'm curious to hear.  Getting "throws" clauses right is pretty  
hard if you try to embed closures in the class system, even with the  
pretty rich set of types we can write down using the where clauses in  
Fortress.

> Missing? Any form of dynamic linkage

This is actually a rather deliberate omission in Fortress.  The  
Fortress language isn't really designed to be the next language for  
dynamic web applications with pluggable functionality.  It is  
designed to run high-performance codes, quickly and reliably.  I hope  
that the Java programming language and VM continue to evolve to do a  
great job on more dynamic problems.  That isn't to say that Fortress  
won't use dynamic linking under the covers---we definitely want to be  
able to compile and optimize components independently where  
possible.  But the programmer's-eye model is that a program doesn't  
change out from under you while it is running.  This enables us to  
exploit a huge number of closed-world assumptions which cannot be  
made by eg your C compiler or a JVM.

> Missing? parametarised throwing of exceptions.

I'm not sure I understand what you want here.  The "throw" clause  
takes an expression of type Throwable as an argument; your exception  
type can have as many fields and parameters and as much state as you  
like.  We don't support C++-like throwing of arbitrary stuff; there  
is a minimal set of functionality we'd like out of every exception.

> Missing? Javadoc equivalent
>
> Very useful.

We agree, but haven't agreed yet on exactly how it should look.  We'd  
like to make use of some of the information inferred by the compiler  
(eg the results of type inference) as part of the generated  
documentation.

> Missing? deprecated
>
> I think this is needed for long term maintenance of APIs

This is more of an issue if you believe that an API can change  
version without changing name.  Our feeling is that programs are  
written and linked against a *particular* API version, which defines  
what it defines.  A component can implement several API versions.

That said, there's going to need to be some thought put into how we  
manage API evolution.  First we need enough APIs to evolve.

> Missing? Annotations
>
> There seems to be no method of modifying the syntax tree after it  
> is generated, syntax expanders are identified and expanded before  
> parsing occurs.

Are you referring to Java-style annotations?  These don't really  
change the syntax tree either, they just add a few hooks to hang user  
annotations on the trees which are already there.

Now, class loaders, *those* can (and do) change the syntax tree.   
Fortress does not have a notion of class loaders (there's the static  
linking again), but we do expect that it will be possible to use the  
interfaces exposed by the language to:
* Parse Fortress and obtain an AST
* Re-write that AST (this would be the programmer's problem)
* Pass the re-written AST to the Fortress compiler directly, without  
generating source code.

> Missing? RTTI
>
> Not needed unless there is dynamic linkage?

I'm not quite sure what you mean here.  It is likely that a fair  
amount of type manipulation will occur at run time, and typecase  
gives hooks to get your hands on quite a bit.  For example, we'd like  
to be able to match generic types in a typecase, and the use those  
parameters in the body; that requires quite a bit of run-time type  
information.

We're also looking at safe ways for providing reflection-like  
facilities.  By "safe" we mean things like "can't change data which  
is expected to remain fixed" and probably "using safer and more  
meaningful keys than just a raw string."  This will be far more  
limited than in Java; we expect to use other techniques (such as  
adding overloadings to existing generic functions) where a language  
like Java tends to make use of reflection.

> Missing? Interface to external code
>
> There seems to be nothing like JNI

Yes, David Chase has done a bunch of work on this, but there's  
nothing final yet.

> various places e.g. section 2.8
> for i ??? 1 : 10 do
>     print(i ??? ???)
> end
>
>
> It seems that juxtaposition of an object with a string converts the  
> object to a string using the Object toString(): String methd. I  
> couldn't find this stated explicitly anywhere. My experience is  
> that though this is OK for quick and dirty output, most of the time  
> formatted IO is much more useful, that is why C style formatted IO  
> was added to Java, it is just too useful.

That is certainly true for numerics.  There is the additional  
problem, though, of matching the type of the data to be formatted to  
the data in the format string itself.  It may be that a *string*  
isn't the right representation here; we're tinkering.

> Section 5.10 String Literals
>
> My experience with Java string literals when used as regular  
> expressions is that they are very difficult to read, as '\' is used  
> as the escape in the string and also as the escape within the  
> regular expression.
>
> My experience with Java string literals is that they are also less  
> than ideal for XML (including XML schema) where " is used  
> frequently as in the value of every attribute.
>
> I think it is worth working out a scheme now to avoid these  
> problems; XML"<atag>....</atag>"XML might work for XML strings.

Novel forms of string literal were definitely on our mind when we  
thought up syntax expanders.  That said, we need to experiment a bit  
to see what really works.  I'd rather we *didn't* parse things like  
XML constants as raw strings to begin with; the hope is that we could  
parse directly to a library representation instead.

> Section 11.5 Operator and Identifier Parameters
>
> property ???(a: T, b: T) a.isLeftZero() ???: ((a ??? b) = a)
>
> should this not be:
>
> property ???(a: T, b: T) a.isLeftZero() ???: ((a ??? b) = b)

No, the latter property states that a is a left *identity*.  Think  
about ??? as being multiplication-like: 0 ??? b = 0.

> Section 12.1
>
> I don't understand the statement "io : Functions that perform  
> externally visible input/output actions are said to be io  
> functions. An io function
> must not be invoked from a non- io function.", How are they to ever  
> be called then?

Well, you're going to have an awful lot of io functions (and methods)  
in your program, none of which can be called from within an atomic  
block.

We're also looking at library designs which might be used to better  
isolate io.  These often have the effect of buffering data until we  
can commit it transactionally.  Using such techniques, we might be  
able to do quite a bit of stuff-which-looks-like-io but which is not  
actually an io action.  It does mean that (eg) we need to dynamically  
allocate buffer space.

> With a function defined as  f(a:ZZ, b:ZZ..., c:ZZ=0, d:ZZ=0)
>
> am I right in thinking that
>     calling f(1,2,3,4,5,6) binds a=1, b=(2,3,4), c=5, d=6
>     calling f(1,2,3,4) binds a=1, b=(2), c=3, d=4
>     calling f(1,2,3) binds a=1, b=(2), c=3, d=0
>     calling f(1,2) binds a=1, b=(2), c=0, d=0
>     calling f(1) binds b=(), c=0, d=0

Hmm, we don't give an example of mixing keywords and varargs in  
section 12.2 of the spec, and we probably ought to fix that.

> Section 13.6 Ranges
>
> I assume that 5:2:-1 will give the same range as 2:5 (except when  
> used in a sequential() generator when it creates the decending  
> sequence 5,4,3,2).

Not quite.  This is a bit subtle, but reduction operations need only  
be associative, and need not be commutative.  The most obvious  
example is list comprehensions:

</ x | x <- 5:2:-1 /> yields </ 5,4,3,2 />
</ x | x <- 2:5    /> yields </ 2,3,4,5 />

That is, the order of elements in the list is preserved, even though  
these elements are being computed in parallel.  (Naturally, our lists  
use a slightly more clever representation than just single links with  
next pointers in order to keep this efficient).

> The range 2:5:-1 does not seem to be ruled out by the definitions  
> in section 13.6, but does not make sense.

Hopefully this makes clear why we might want both.

> Is it possible to use ranges to create infinite sequences? Does  
> sequential(2:) start at 2 and increment indefinitely?

No, there isn't currently a notion of an infinite sequence, in part  
because there isn't a clear notion of how to parallelize such a thing  
in a reasonable and obvious way.

> Section 13.12 & 13.14
>
> I expect that
>
> while Expr do
> ...
> also do
> ...
> also do
> ...
> end
>
>
> the while loop is to the end, not to the first also do.

Yes.  The "while" body continues until the enclosing "end".  But you  
made me double-check the grammar just to make sure. :-)

> Section 22
>
> Am I right in thinking that APIs can never be upgraded?
>
> I would have hoped that a version 2.0 of an API that extends  
> version 1.0 could still be imported wherever used. Something like:
>
> component Com.Sun.IronCrypto
> import Fortress.IO.1.0
> import Fortress.Security
> export Fortress.Crypto
> . . .
> end
>
> api Fortress.IO.2.0 extends Fortress.IO.1.0
> ...
> end
>
> otherwise the Java situation of having to add extra interfaces to  
> avoid extending existing ones will occur.

Remember that we can't depracate 1.0 functionality in 2.0.  Instead  
we describe Fortress.IO.2.0 as an entirely new api (probably with  
heavy name and type overlap with 1.0).  Then our component has the  
opportunity to export both:

component Fortress.IOLibrary.2.0
export Fortress.IO.1.0 (* For backwards compatibility *)
export Fortress.IO.2.0

...
end

> I may have missed it but is there any way of distributing  
> components in other than source form? If user A creates a compound  
> component is there any way for him to distribute it to user B other  
> than in source form and a sequence of compile, link, upgrade  
> commands? Are these compile, link, upgrade, etc. commands  
> guaranteed to give the same composite component for user B?

Components can be serialized, but I'll admit that we haven't worked  
out all the representation details; for the moment we intend our  
prototype to just use source code to represent components, possibly  
with a pre-parsed AST form as an alternative.  Anything we use is  
going to be pretty close to source code for the time being (so it  
should be possible to do AST->AST rewriting passes on existing  
components for example).

> E2
>
> should
> opening comment delimiter ???*(??? changes
> not be
> opening comment delimiter ???(*??? changes

Yes, it should.

Thanks for the detailed comments.  I hope I was able to clear up a  
few of your questions.

-Jan-Willem Maessen






This page is: http://www.experimentalstuff.com/pipermail/fortress-interest/2007-January/000065.html
Last Modified: Thu, 04 Jan 2007 16:36:02 GMT
copyright (c) 2000-2009, Sun Microsystems