Forums

Conditional compilation

General discussion about Cobra. Releases and general news will also be posted here.
Feel free to ask questions or just say "Hello".

Conditional compilation

Postby hopscc » Wed May 23, 2012 5:19 am

I've not used the @help directive ( Noted here and originally discussed and announced here) very much - it doesnt match how I work or lookup stuff but the syntax/concept is interesting and could be extended to a couple of other convenient things.

1. Debugging
Specify some code to be included/executed (displayed) if debug is enabled when the compiler is run
e.g.
result = .aVeryBigCalc(a1, a2, a3)
@debug print .prettyFormat(result)
... # do something with result


If -d compiler flag is specified when the code is compiled, the expressions and statements prefixed by @debug will be compiled into the generated exe.
If debug is not specified the prefixed code will be ignored.
( the above example duplicates trace ( sort-of, without some gingerbread) but it doesn't need to be limited to only display

2. Platform specific code
Prefix lines with a tag indicating the following code is only generated specific to a particular platform/back-end
simple e.g
# platform varying Hello world
namespace Test
class Test
def main is shared
@platform-clr Console.writeLine('Hello, world.')
@platform-jvm System.out.println('Hello, world.')
@platform-other assert false, 'Need platform display output call'


in the above, the writeline line is only compiled/code generated for a backend .Net/CLR build,
the println line is similarly only included for a backend jvm build
( the -other is a catch all if nothing else is previously matched)

This comes from modifying the cobra test code to work with a java build/back-end compile
- In many cases the test code uses/relies on platform library calls (mostly peripheral to what the tests are verifying).
The current resolution is either split the file into platform dependent and independent parts or duplicate the file - change the platform dependent calls for the platform and tag (compiler directive) the files so that they are only compiled if the back-end compile matches the tag setting.

The above directives gives a more granular approach to some form of multi-platform support ( as a interim step before a full platform independent library exists).

FWIW I think the D language has a similar construct for specifying conditional compilation D Conditional Compilation
hopscc
 
Posts: 632
Location: New Plymouth, Taranaki, New Zealand

Re: Extending @help directive concept

Postby Charles » Wed May 23, 2012 11:52 am

Should we have @if like C#'s #if?
Charles
 
Posts: 2515
Location: Los Angeles, CA

Re: Extending @help directive concept

Postby hopscc » Wed May 23, 2012 11:03 pm

Preferably not.

For the purposes/uses I've been using cobra for to date, something along the lines of the items given above providing lines (and blocks) of conditionally compiled or ignored code would be simpler and clearer both to use and read - and avoid more complex arbitrary combinatorial possibilities

The only addition I'd make over the above would be provision of a similar construct triggered by something passed to the compiler environment
(env variable or arbitrary command-line tag setting,...).

I like the D approach of wrapping the cond-compile code in a (single or multi-line) block headed by (only a simple) control variable..
Easy tests (debug, supported platform) are simple and clear, complex ones are possible via nesting the blocks if necessary.

(Having said the above though I've not fully thought through how fall through or the final else of an if..elif..elif... else ... setup would be done)
hopscc
 
Posts: 632
Location: New Plymouth, Taranaki, New Zealand

Re: Extending @help directive concept

Postby Charles » Thu May 24, 2012 12:32 am

Also, were you planning that there could be multiple statements like so?
def main
@platform-clr
Console.writeLine('Hello')
Console.writeLine('Goodbye')

And could these be applied to declarations?
def foo is @platform-clr
pass
def foo is @platform-jvm
pass
Charles
 
Posts: 2515
Location: Los Angeles, CA

Re: Extending @help directive concept

Postby hopscc » Fri May 25, 2012 4:14 am

yes (eventually) for the multiple statements (block) - thats liable to be useful/necessary for more complex systems

yes for declarations though not in the way you specified - i.e not embedded within a line
applies to a single line or a (syntactically valid/complete (parse Node)) block of code

e.g.

class CList
@platform-clr var x as System.Collections.ArrayList = ArrayList()
@platform-jvm var x as Java.Util.List = Vector()


def prependX(item as CollItem) is protected
@platform-clr .x.insert(0,item)
@platform-jvm .x.add(0,item)
...


Idiomatically a clearer way of doing same would probably be platform specifically coded separate complete classes (blocks)

@platform-clr
class CList
var x as System.Collections.ArrayList = ArrayList()

def prependX(item as CollItem) is protected
.x.insert(0,item)
...

@platform-jvm
class CList
var x as Java,Util.Vector = Vector()

def prependX(item as CollItem) is protected
.x.add(0, item)
...
hopscc
 
Posts: 632
Location: New Plymouth, Taranaki, New Zealand

Re: Extending @help directive concept

Postby hopscc » Tue Jan 08, 2013 6:37 am

I had a bit of time over the last two weeks and I've implemented some conditional compile directives for cobra.

These are done by specifying one of 3 prefixes after an '@' at a statement, BoxMember or Namespace member level
Correctly formed code indented under these directives is parsed and if the conditional-compile condition evaluates true
the code is included in the parse tree for codegen, If not it's dropped.

The directives are
Code: Select all
@debug
@ver # for versioning ( see D )
@env # for testing for, or value of, an environment variable


If debug (existing -d) is on for a compile ( default) then statements and blocks under an @debug are compiled into the generated code.
If debug is turned off ( -d:0) then these statements and blocks will be ignored.

Is use of existing -d switch ( puts debug meta info into generated executable file) acceptable or would it be better to have an additional ( new) switch to enable/disable this?

Heres a simple example
class DbgDir
def main is shared
a = 99
@debug
print a
a = 40 # debug only code perturbation
assert a == 40

or perhaps more usefully

class DbgDir
def main is shared
a = ... somecalcOfValue..
@debug print a
a = ... somecalc ...


The second form ( @ver) is for using predefined and builtin platform and compiler option identifiers.
Eventually it could/should also support items set with a compiler commandline switch ( -define:<name> ) but my implementation doesnt do this yet..
Is that level of flexibility necessary??

The version variables to test are given after the @ver separated by a DOT ( giving a sort of namespace)
@ver.clr a = System.Collections.ArrayList()
@ver.jvm a = Java.Util.Vector()


Supported values so far are
  • clr - enabled if using clr backend
  • jvm - enabled using jvm backend
  • objc - enabled if using onjc backend ( NYI)
  • dotnet - enabled if on dotnet platform
  • mono - enabled if on mono platform
  • windows - enabledif on windows platform
  • unix - enabled if on unix platform
  • mac - enabled if on Mac platform
  • asserts - enabled if asserts enabled ( -include-asserts)
  • tests - enabled if tests enabled ( -include-tests)
  • contracts - enabled if contracts enabled ( -include-contracts)
  • always - always enabled as contrast to
  • never - always disabled, cond compile out an a block of code

These are the existing builtin platform/backend/config setups already in cobra ( except for always and never).
Are these sufficient for builtin/predefined versioning values ?

heres an example of use
class Test
def main is shared
@ver.jvm System.out.println('Hello, world.( System only)')
@ver.clr Console.writeline('Hello World')

One additional thing thats perhaps useful and missing is some provision for an 'other/else' case that matches when no other clauses do..

and
for i as int in 1 : 10
x = i
@ver.clr
continue
@ver.jvm
if true, continue
count += 1 #unreachable statement - gives error msg in java
assert x==9
assert count==0


The third form uses @env to test an environment variable being set or that it has a particular value
The env var name follows a DOT after '@env', any value to test against follows a DOT after that ( either quoted or not)
@env.HOME
print 'Home env variable set'
@env.HOME.'/home/hops'
print 'Home env var was /home/hops at compilation'

Conceivably this could be used for code config/selection at build time triggering off an environment variable setting (rather than a compiler define option)

Does anyone have any opinions as to this naming form ( prefix, DOT separated, variableName, optional value) or
preferences/suggestions for different/better prefix values?

I'll open a ticket for this.
hopscc
 
Posts: 632
Location: New Plymouth, Taranaki, New Zealand

Re: Extending @help directive concept

Postby hopscc » Tue Jan 08, 2013 6:55 am

Opened on ticket:312

One other thing I havent mentioned that may be a useful addition is to conditionally compile on a version-number.
If a defined or accessible (env variable) value is greater than a value given in code then compile the code clause

@ver.OSVer.'0.5'
ver = 'beta or pre beta Version'
@ver.OSVer.'1.0'
ver = 'v1.0 or greater'
@ver.OSVer.'1.2'
ver = 'v1.2 or greater'
print 'Version:[ver]
hopscc
 
Posts: 632
Location: New Plymouth, Taranaki, New Zealand

Re: Extending @help directive concept

Postby Charles » Tue Jan 08, 2013 2:32 pm

I have lots of thoughts and strong opinions here.

The previously described approach seems suboptimal compared to an @if-based approach in the following ways:

-- I don't see any way to do an "OR" condition.

-- There is no @else (which you point out). Of course, if you add an @else, then @if becomes more natural.

-- @env.HOME.'/home/hops' seems like obscure syntax and precludes other kinds of comparisons like "does not equal"

-- If @env.VAR.'value' means "equals to" then it is not clear that @ver.OSVer.'1.0' means "equal to or greater" since it is the same syntax.

-- Also, the word "version" (or "ver") doesn't conceptually describe "clr" and "jvm". Version is most often thought of as "0.9.3". If you asked someone for a description of "clr" or "jvm", the most likely words would be "platform", "vm", or "back-end".

The foundation of conditional compilation should be @if with conveniences added where we want them. In fact, this is what D does (see http://www.digitalmars.com/d/1.0/version.html and scroll down). C# does this to some extent as well with their support of #if as well as the Conditional attribute. Actually Conditional goes further by silently eliminating the calls which I can see the handiness of.

Here is the form for a Cobra @if:

Code: Select all
@if <condition>
   <code>
@else if <condition>
   <code>
@else
   <code>


The "@else if" and "@else" parts would be optional.

<condition> can be:
    true
    false
    comparison (== <> < > <= >=)
    compound (and or)
    not <condition>
    string literal
    .METHOD(ARGS)
    parens for grouping
Let's list what's required to be able to check:
    Cobra version
    Platform (jvm, clr)
    Env vars
    Debugging on or not
    Assertions on or not
    Trace on or not
    etc.
The "Debugging on or not, etc." can all be done through symbolic definitions (DEBUG, ASSERT, TRACE, CONTRACTS).

So then methods would be:
.defined('FOO')
.environ('FOO')
.definedOrEnviron('FOO')
.cobraVer
.platform
.opSys

It might be overkill to have "version objects", arithmetic, etc. which means we could get by with just == and <> for comparisons and then have methods like:
.cobraVerOrHigher('0.9.1')
.cobraVerHigherThan('0.8.x')

We could provide a convenience to say FOO instead of .defined('FOO') similar to C#'s #if which makes things more tidy:
@if DEBUG ...

Even if our early implementations don't support all of the above, we should design for these capabilities ahead of time and have a structure that can grow into them. We could skip paren grouping and even "and" and "or" in early implementations as adding them later would not break anything (other than having defines called "and" and "or" which is highly unlikely for two reasons).

There would also be @define and @undefine.

Also, I don't think it's important that @if enable tricky things like starting or not starting a comment, multiline string, etc. It does not need to be separate from the tokenizer.

Here is some info on how C# does it:

http://msdn.microsoft.com/en-us/library/ed8yd1ha.aspx
http://msdn.microsoft.com/en-us/library ... 94(v=vs.71).aspx

Also, any implementation needs a lot of tests. I found a couple bugs in Cobra just the other day. I'm trying to resolve this situation and get to 1.0 by emphasizing fixes over new features. Adding new features introduces new bugs. Lots of tests will be required.

Regarding conveniences, we don't really need any for debug which would just be:
@if DEBUG
<code>

Platform is more involved:
@if .platform == 'jvm'
<code>

So I guess then:
@platform (jvm|clr)
<code>

I'm doubtful we need a "one line" form like what you showed for your var decls. I would just make those separate classes anyway.

I would get @if working first and add convenience forms conservatively.

Btw I know that my .opSys is vague and may be need to broken out into other things. But it's also an example of something we can implement later without breaking this structure.

I'm sure I missed some other things in this post, but it's a start.

Using @if/@else if/@else and expressions as a foundation seems fundamentally useful and clear. You'd have to talk me out of it.

P.S. The title for this thread is weird. This isn't about extending the @help concept. It's about new directives for conditional compilation.
Charles
 
Posts: 2515
Location: Los Angeles, CA

Re: Extending @help directive concept

Postby hopscc » Tue Jan 08, 2013 8:43 pm

Starting from the end
P.S. The title for this thread is weird. This isn't about extending the @help concept. It's about new directives for conditional compilation.


If you reread the earlier posts you'll see its more about using the keyword + line (extended to a block) syntax structure concept to provide conditional compilation (rather than an extension to help per se)
This is as opposed to implementing the same C-like preprocessor-ancestry general purpose variable set-unset and test branching structure. The problems issues and pitfalls of this are well known and later languages have all moved away from that concept ( at varying rates..)..

Actually this is all based loosely on D ( version2 of the lang rather than the 1.0 ref you linked to - not that theres very much difference/change)

Now to your points:
No OR / or ELSE

thats because theres no explicit 'if' or <condition>.
This is more oriented around a block (or statement or decl(s)- dont worry about the granularity)
thats triggered from a (fixed) condition tag - Its definitely not directed towards arbitrary complex use as a general purpose branch-with-attendant-conditions setup

The 'conditional' in conditional compilation here is more to 'match' to a situation
( on a particular platform/backend, match to a user setting or a compiler setting) than a binary test of a boolean expression

env.var.'value' re other comparisons

there are no other comparisons - it matches or it doesnt.
(The number versioning was an afterthought - not sure its necessary or if need comparison to version numbers'
but could be done a similar way with something modifying what a match means
Code: Select all
env.OSVer.'>=1.0'

as a rough (and poor) example.

The intention here is for something short and direct and keyword/tag like (that isnt similar to a binary condition).

word "version" (or "ver") doesn't conceptually describe "clr" and "jvm". Version is most often thought of as "0.9.3'

The second bit is a version-number not a version.
This is version as in any conditional compilation makes a different version of the executable.
- version for jvm
- version for mono
- version for windows, ...

So no it doesnt describe the mechanism being tested/used, it describes the goal.
'a version specific to something'

The foundation of conditional compilation should be @if with conveniences added where we want them. In fact, this is what D does (see http://www.digitalmars.com/d/1.0/version.html and scroll down)

The first sentence is an assertion not an argument.
The second sentence is factually correct but incomplete.
Its one of the things D does. (after scrolling down) and it seems the least important one - the same page refers to 'Version Conditions' and 'Debug Condition' which are block oriented and more similar to the selection of code to compile we're after here.
No if-conditions for these common (and simple) cases.

- I'd say static-if in D was more for the benefit of their version of templating than conditional-compilation in that it tests compile time constants and a condCompile is directed by setups/config outside the codebase (target platform, user spec build defn passed into compiler,...)

.. description for reinvention of same-old C-preprocessor-like-ifdef for cobra elided....
I dont believe this is a desirable way to go for the most common cases
(code selection for platform, back-end, Debugging, compiler-setups).
At the very least its overly general purpose and complex for the need desired and subject to the same old problems and abuses...
Cobra deserves something simpler and clearer which tag-match-and-block definitely is.


The only thing to check for condCompile I havent covered is versioning on Cobra version (or more specifically cobra features per version).
Primarily I'm not sure its necessary ( at least it has not been to date) but over that
testing version and applying code specific to that version is not desirable to direct developers toward doing.
Pitfalls of this are well known as well.
Better is to form a code structure that ties versions to features then codes to the features
( as per the example on the D page just under 'Version Specification') - providing capability to do this would suffice for most uses
alternatively compiler could expose major feature items as condCompile match tags same as doing for platform/backend tags
(hasLambda, hasMethodInference, hasLiteralCollectionTyping...) assuming we can get some agreement of what constitutes a new major feature.

I agree that condCompile directives are not arbitrarily positionable - my impl has them only recognised in 3 places
(at statements, BoxMember decls, NSMember decls) - they're not separate from the tokeniser and recognised as unique parser items.

Also, any implementation needs a lot of tests. I found a couple bugs in Cobra just the other day. I'm trying to resolve this situation and get to 1.0 by emphasizing fixes over new features. Adding new features introduces new bugs. Lots of tests will be required

yeees.. There are tests with this covering all the inflection points as per usual - adding 'lots' probably wont improve coverage appreciably. This is same situation as everywhere else.
I'm not sure of your point here:
  • there are bugs ?
  • adding things introduces bugs?
  • need more tests?
  • no new features ?
  • No code without tests ??
I agree that there is certainly no shortage of fixes waiting for something to be done with them without considering new features.
(OTOH having some simple form of condCompile would simplify porting tests for java backend massively so I'm scratching my own itch here)

I'm doubtful we need a "one line" form like what you showed for your var decls

Actually thats very useful - most noticeably with debug type output but also (wrt java port of tests) where theres a small one line tweak needed for support of different backends - saves a split of testfiles into two platform specific files or method differing in only a single line.
Its necessarily available for use, use of it is not mandated.

I would get @if working first and add convenience forms conservatively.

Aaah - I'm coming from the opposite position.
The 'convenience' forms (as you describe them) aren't - they are are the most-used core for condCompile (at least as it is now).
Only provide @if-@then-@else more general form for situations where the tag-match-and-block forms are totally unworkable.
(I'm not convinced thats the case or that the general form is advantageous in any form)

re OpSys.
For comparison most of the predefined version Identifiers in D are for specific OPSys implementations ( e.g Solaris vs 'unix')
cobra (currently) only supports 3 families (windows, mac and unix)
Will we (eventually perhaps) also need to become exactly platform/hardware/... specific for these builtins also (systems programming)?

Using @if/@else if/@else and expressions as a foundation seems fundamentally useful and clear


We're agreed on fundamentally useful (some form of condCompile). Clear - no
tagged-match and block-code is definitely clearer, cleaner and also stands out from cobra exec code (compared to cobra if-else branching).

I'll post the patch on the ticket and you can see some condCompiled test code.

I asked some specific questions in my earlier post - those were some directions I was wondering about since I thought I'd already clarified the general approach I was heading with this earlier.

(this is probably enough of a post for now - more later if I come up with anything else).
hopscc
 
Posts: 632
Location: New Plymouth, Taranaki, New Zealand

Re: Extending @help directive concept

Postby hopscc » Tue Jan 08, 2013 8:56 pm

Was going to mention something about @env.
wrt the above @env is a bit of an aberration

was originally going to do it all via @ver
@ver.env.NAME.VALUE
<code block>
@ver.env.HOME.'/usr/hops'
print 'hops has a home dir in std place'


but thought that was getting a bit long and convoluted in appearance.

Use of env is a replacement for not having a compiler cmdline option to pass arbitrary setting to compiler run
( -define:NAME[=VALUE]) say
so was considering it temporary till decide whether that's necessary.

Its not uncommon to use environ variables to control builds and code included (rolled into the codebase directly( C preprocessor) )
but not sure that its necessarily a desirable feature to support (for cobra at least).
hopscc
 
Posts: 632
Location: New Plymouth, Taranaki, New Zealand

Next

Return to Discussion

Who is online

Users browsing this forum: No registered users and 107 guests