Blog Post

#462 Build 1.0.38

brian Mon 16 Feb 2009

It has been about a month since build 37, so I've posted a new build. This past month we've been pretty engrossed in coding Bespin, so there aren't a lot of language changes. But this build includes a lot of API and compiler tweaks as we've been putting Fan thru its paces.

Breaking Changes

Breaking changes you should be aware of:

The web Cookie API was refactored to deal with the sloppy way IE and Safari implement cookies. Cookie is now a const class which enforces the value to be ASCII chars legal for a quoted string, although the semi-colon is disallowed since IE doesn't parse quoted strings correctly.

There are several breaking changes to the webapp::Widget class as Andy refactors things to support Fan to JavaScript.

Also the Json.write method had its parameters switched, so now you do:

json::Json.write(Sys.out, [1,2,3])

Expr Return

You can now omit the return keyword when returning an expression as long as your method or closure has exactly one statement:

Int area() { w * h }
files.sort |File a, File b->Int| { a.modified <=> b.modified }

See discussion. See docs.

Const Mixins

Mixins can now be declared const. This lets you use the mixin in const fields and forces all implementing classes to also be const.

Const Overrides

One of the very cool things Fan lets you do is override a no-parameter method with a field. However, I found myself wanting to do this often with a const field. This is now allowed, and the compiler will generate a getter method to implement the override. A common pattern where I've been using this technique:

const mixin Rec
{
  abstract Str id()
}

class const RecImpl : Rec
{
  override const Str id
}

See docs.

API Changes

There are oodles of new convenience methods on the core types. A small set of core types combined with lots of convenience methods really aids the ability to chain methods together. I'm finding this has great power to cut down the number of lines of code used.

Using strings with IO APIs:

xml::XParser("<foo/>".in).parseDoc.write(Sys.out)
"Brian Frank".toBuf.toBase64

Converting strings to/from camel case:

"statusValue".toDisplayName     =>  "Status Value"
"Status Value".fromDisplayName  =>  "statusValue" 

New Buf methods:

Buf().fill(0xf0, 4).toHex  => "f0f0f0f0"
"hi there".toBuf.hmac("MD5", "secret".toBuf)  // hmac commonly used for auth

New to/from ISO methods on date time types (commonly used in XML):

DateTime.now.toIso          =>  "2009-02-15T19:05:05.01-05:00"
Date.now.toIso              =>  "2009-02-15"
Date.fromIso("2009-02-15")  =>  2009-02-15   

For a while now you've been able to configure a map to use case insensitive keys. Now you can configure a map to keep its values ordered by insertion (uses LinkedHashMap under the covers):

map := Str:Str[:] { ordered = true }

I keep founding myself wanting to turn a list into map, which you can now do with addList and setList. For example to find all methods on Str with no parameters, then turn that into a map keyed by slot name:

list := Str#.methods.findAll |Method m->Bool| { m.params.isEmpty } 
map := Str:Method[:].addList(list) |Method m->Str| { m.name } 
echo(map.join("\n"))

New verification methods on Test:

verifyNull(expr)
verifyNotNull(expr)

New sys::Unsafe wrapper class as discussed to wrap a mutable object to pass where immutable is expected:

Unsafe wrapper := thread.sendSync(Unsafe(mutable))
return wrapper.val

Over and over I again I find myself declaring a empty list of a specific type I can reuse to save memory. Now you can use the new Type.emptyList method to get a singleton immutable list reused for the whole VM:

Widget[] children()
{
  if (kids == null) return Widget#.emptyList
  return kids.ro
}

We've talked about the ability to format a value according to its code representation. I've added a toCode method to most core types which return their Fan code representation . You can use this method with duck typing:

[true, "hi", Date.today, `file.txt`].each |Obj o| { echo(o->toCode) }
true
"hi"
Date("2009-02-15")
`file.txt`

Often when you are doing meta-programming you need to create default values for common types. This is now standardized into the API. If you create a field or method called defVal, then Type.make will attempt to use that if your class doesn't provide a constructor/factory called make. All of the common types like Bool, Str, Int, etc provide a defVal now:

[Bool#, Int#, Str#, Uri#].each |Type t| { echo(t.make->toCode) }
false
0
""
``

Doc Compiler

There is a new @nodoc facet you can apply to types and slots to have them omitted in the documentation. This facet is an indication of a public type or slot which should not be considered part of the pod's public API. See doc.

oBIX

I've started the obix API for Fan. oBIX is an OASIS standard for the M2M industry which I authored. But the core spec is just a generic framework for defining data models with prototype inheritance and encoding to XML (it is inspired by Self). I designed oBIX to enable high fidelity with heterogeneous data models which might be both statically or dynamically typed. The oBIX spec colors a lot of what I do in Fan, for example the unit database is also based on oBIX. You can download the spec from here.

What I have right now is basic object XML encoding/decoding. Shortly I will be adding support to round-trip serializable Fan objects to XML without loss of type information. I will also be creating some weblets to make it easy to expose Fan objects via a REST interface using the oBIX REST/SOAP model.

Fan to JavaScript Compiler

Andy has been busy on the Fan to JavaScript compiler. It includes a Fan API for working with the DOM in the browser called webappClient which matches up with the server side framework in webapp. All of our AJAX code for Bespin is being written in Fan - its very cool. I'll let Andy blog about when he feels it is ready for people to try out.

Change Log

Build 1.0.38 (15 Feb 09)

  • Str: in, toBuf, toDisplayName, fromDisplayName
  • Buf: dup, fill, hmac
  • Duration, DateTime, Date, Time: toIso, fromIso
  • Map: ordered, join, setList, addList
  • Test: verifyNull, verifyNotNull
  • Type: make support for defVal
  • Type: emptyList
  • MimeType: charset, parseParams
  • Add toCode: Bool, Int, Float, Decimal, Uri, Duration, DateTime, Date, Time, List, Map
  • Unsafe wrapper class
  • New compilerJavascript and webappClient APIs
  • New obix API
  • Rework webapp APIs
  • Doc compiler support for @nodoc facet
  • Web Cookie refactor into const class
  • Web Cookie enforce name and value chars and use quoted string value
  • Web Cookie fix use both max-age and expires for cookies for IE and Safari
  • More linux timezone work arounds
  • Json fix for parsing top level array
  • Json.write API change
  • Flux add findInFiles into context popup of dirs
  • Flux fix undo/redo stack to check point on save
  • Flux syntax definition for ActionScript
  • Compiler allow single statement expression based return
  • Compiler allow const field to override a method
  • Compiler fix when local variable shadows field with storage operator
  • Compiler fix when using null safe call with no-leave primitive return
  • Compiler fix when calling super with default params results in stack overflow
  • Compiler fix allow mixins use const keyword
  • Compiler fix for once methods used with subclasses in same pod
  • Compiler fix for construction call against fromStr in super class
  • Compiler fix to check for dup method params and dup enum defs

JohnDG Tue 17 Feb 2009

Looking forward to see the JavaScript compiler. You might want to take a look at Java2Script, which provides a JavaScript-based implementation of SWT. Since FWT uses SWT underneath, depending on the Java2Script license, it might be possible to use their work to produce a JavaScript-backed version of SWT. This way clients could use the same API whether writing for desktop or web applications.

Login or Signup to reply.