Skip to content

Latest commit

 

History

History
157 lines (122 loc) · 4.2 KB

007-version-blocks.md

File metadata and controls

157 lines (122 loc) · 4.2 KB

Version blocks

Syntax

Version blocks use the following syntax:

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

Where 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
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
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. It is common practise for ooc developers to use the -Ddebug switch to debug their applications.

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
	}