Skip to content

Commit

Permalink
we have else on versions
Browse files Browse the repository at this point in the history
  • Loading branch information
roja committed Oct 5, 2010
1 parent d2e3d03 commit 0930a44
Showing 1 changed file with 155 additions and 146 deletions.
301 changes: 155 additions & 146 deletions version-blocks.md
Original file line number Diff line number Diff line change
@@ -1,147 +1,156 @@
Version blocks
==============

Syntax
------

Version blocks use the following syntax:

version (<version expression>) {
<body>
}

Where <version expression> can be any of:

<version name>
!<version expression>
<version expression> && <version expression>
<version expression> || <version expression>

Semantics
---------

Version blocks aren't if-else blocks - they aren't evaluated at runtime.
In rock, version blocks aren't evaluated at ooc-compile-time either.
They're evaluated at C compile time. Which means the C code generated by rock
should be the same on any platform.

Practically, in rock, version blocks are an abstraction for #ifdef / #endif blocks.
The syntax makes it harder to forget to close a version block than an #ifdef / #endif block,
and a few handy aliases (listed below) for commonly used version names are standard, so that developers
don't have to remember the convoluted corresponding C defines.

For other compilers not based on the C language, version block handling may happen at any
stage of the compilation (if any), as long as the version expressions are correctly evaluated
and have the correct meaning (for example, a 'windows' version block should be ignored on OSX)

Built-in version names
----------------------

C defines are included here for completeness, but are only relevant for people who want
to implement ooc on top of C.

|Name |corresponding C define |
|:-----:|:---------------------:|
|windows|__WIN32__ || __WIN64__ |
|linux |__linux__ |
|solaris|__sun |
|unix |__unix__ |
|beos |__BEOS__ |
|haiku |__HAIKU__ |
|apple |__APPLE__ |
|gnuc |__GNUC__ |
|i386 |__i386__ |
|x86 |__X86__ |
|x86_64 |__x86_64__ |
|ppc |__ppc__ |
|ppc64 |__ppc64__ |
|64 |__x86_64__ || __ppc64__|
|gc |__OOC_USE_GC__ |

Custom version names
--------------------

Most of the standard version names above depend on your building environment, and the 'gc' name depends
on the compiler setting -gc=[off,static,dynamic].

Custom version names can be used, and turned on/off with the -D and -U compiler flags, for example:

version(debug) {
"[%d] Saving database %s" println(timestamp(), db name)
}
db save()

The code inside the version(debug) block will be compiled if -Ddebug is used.

Semantics continued
-------------------

Version blocks can be used in function bodies, to make certain parts of the code OS-specific, or
they can be used at the mdule-level to make functions or types OS-specific.

If different types are defined in different version blocks, make sure they expose the same interface.
It's not necessary for them to have the exact same class layout, but they should at least have all the
methods/fields that are used in every OS.

Examples
--------

version(windows) {
"Hi, Bill!" println()
}
version(apple) {
"Hi, Steve!" println()
}
version(linux) {
"Hi, Linus!" println()
}
version(!windows && !apple && !linux) {
"Who are you, and what did you do to my OS?"
}

See also io/File and os/Time in the SDK for real-world examples of heavily versioned code.

Pattern for OS-specific classes
-------------------------------

In ooc, 'new' isn't a keyword but a static method. As a result, you can define new yourself.
This allows an interesting pattern for OS-specific classes in ooc:

// io/File
import io/[FileUnix, FileWin32]

File: class {
path: String

new: static func (.path) -> This {
version(windows) { return FileWin32 new(path) }
version(unix) { return FileUnix new(path) }
Exception new(This, "Unsupported platform") throw()
}
// abstract methods
}

// io/FileUnix
FileUnix: class extends File {
init: func (=path) {}
// implement abstract methods for unix
}

// io/FileWin32
FileWin32: class extends File {
init: func (=path) {}
// implement abstract methods for Win32
}









Version blocks
==============

Syntax
------

Version blocks use the following syntax:

version (<version expression>) {
<body>
} else {
<alternative body>
}

Where <version expression> can be any of:

<version name>
!<version expression>
<version expression> && <version expression>
<version expression> || <version expression>

Semantics
---------

Version blocks aren't if-else blocks - they aren't evaluated at runtime.
In rock, version blocks aren't evaluated at ooc-compile-time either.
They're evaluated at C compile time. Which means the C code generated by rock
should be the same on any platform.

Practically, in rock, version blocks are an abstraction for #ifdef / #endif blocks.
The syntax makes it harder to forget to close a version block than an #ifdef / #endif block,
and a few handy aliases (listed below) for commonly used version names are standard, so that developers
don't have to remember the convoluted corresponding C defines.

For other compilers not based on the C language, version block handling may happen at any
stage of the compilation (if any), as long as the version expressions are correctly evaluated
and have the correct meaning (for example, a 'windows' version block should be ignored on OSX)

Built-in version names
----------------------

C defines are included here for completeness, but are only relevant for people who want
to implement ooc on top of C.

|Name |corresponding C define |
|:-----:|:---------------------:|
|windows|__WIN32__ || __WIN64__ |
|linux |__linux__ |
|solaris|__sun |
|unix |__unix__ |
|beos |__BEOS__ |
|haiku |__HAIKU__ |
|apple |__APPLE__ |
|gnuc |__GNUC__ |
|i386 |__i386__ |
|x86 |__X86__ |
|x86_64 |__x86_64__ |
|ppc |__ppc__ |
|ppc64 |__ppc64__ |
|64 |__x86_64__ || __ppc64__|
|gc |__OOC_USE_GC__ |

Custom version names
--------------------

Most of the standard version names above depend on your building environment, and the 'gc' name depends
on the compiler setting -gc=[off,static,dynamic].

Custom version names can be used, and turned on/off with the -D and -U compiler flags, for example:

version(debug) {
"[%d] Saving database %s" println(timestamp(), db name)
}
db save()

The code inside the version(debug) block will be compiled if -Ddebug is used.

Semantics continued
-------------------

Version blocks can be used in function bodies, to make certain parts of the code OS-specific, or
they can be used at the mdule-level to make functions or types OS-specific.

If different types are defined in different version blocks, make sure they expose the same interface.
It's not necessary for them to have the exact same class layout, but they should at least have all the
methods/fields that are used in every OS.

Examples
--------

version(windows) {
"Hi, Bill!" println()
}
version(apple) {
"Hi, Steve!" println()
}
version(linux) {
"Hi, Linus!" println()
}
version(!windows && !apple && !linux) {
"Who are you, and what did you do to my OS?"
}


version(apple) {
"Nice Hardware!" println()
} else {
"So you like your computer made of plastic then!" println()
}

See also io/File and os/Time in the SDK for real-world examples of heavily versioned code.

Pattern for OS-specific classes
-------------------------------

In ooc, 'new' isn't a keyword but a static method. As a result, you can define new yourself.
This allows an interesting pattern for OS-specific classes in ooc:

// io/File
import io/[FileUnix, FileWin32]

File: class {
path: String

new: static func (.path) -> This {
version(windows) { return FileWin32 new(path) }
version(unix) { return FileUnix new(path) }
Exception new(This, "Unsupported platform") throw()
}
// abstract methods
}

// io/FileUnix
FileUnix: class extends File {
init: func (=path) {}
// implement abstract methods for unix
}

// io/FileWin32
FileWin32: class extends File {
init: func (=path) {}
// implement abstract methods for Win32
}










0 comments on commit 0930a44

Please sign in to comment.