Macros?

BlitzMax Forums/BlitzMax Beginners Area/Macros?

ImaginaryHuman(Posted 2005) [#1]
Macros. Back in my assembly language days, macro's were a useful feature and supported by the assembler/compiler. You could define a chunk of code in one place and then `insert` that code at any place by just calling the macro. And of course you could have nested macro's, and also conditional macro's using If-Then-Else stuff. Presumably this was more useful for assembler code since it was so low-level, the trend was towards fast in-lined code and because asm programs could be so long and complicated.

Well anway, I thought macros would be a nice addition to either the BlitzMax IDE (or another IDE such as Protean - haven't tried it or checked if it does this), or to the BlitzMax compiler (or as a pre-compiler?). This would then allow the programmer to maintain a piece of code in one place that can be in-lined wherever needed. It's a different way to go about things rather than lots of function calls.

I'm a little concerned with the fact that BlitzMax is abstracted from the hardware as it is. In other words, in order to implement a lot of functionality, a lot of it is written IN BlitzMax, and a lot of the functions call other BlitzMax functions themselves. This is adding extra overhead and distancing the user from the raw hardware. It's all very well abstracting things and making it higher level but there is a speed expense. And now I also see people throwing around the idea of creating a `wrapper` module like nobody's business, even though that will likely add yet more layers of nested function calls.

With macro's you would be able to easily in-line code and functionality rather than needing to make more calls to a stack. One idea I came up with to temporarily work around this is if you wanted to rename some of the tokens .... you could create a piece of code to define function pointers which you then proceed to re-map to the actual functions you want them to call, at runtime, before they are called. You could then use these re-named tokens in your programming (unless I overlooked some compiler issue). For example you could then use different wording for the OpenGL commands if you wanted to (some of them are not labelled entirely to my liking). This techinique would at least give you a limited piece of the functionality that macros would give you, and for such an application you wouldn't need to create yet another module that only ends up calling a function from within a function. Looking through the BlitzMax modules there's several instances where you call something that just calls something else which calls something else, all different names. No needed.

But anyway. How about macro functionality for BlitzMax programs?


flying willy(Posted 2005) [#2]
Thumbs up - I used these on the Amiga version of Blitz.


jhague(Posted 2005) [#3]
I agree, macros would be useful, but AngelDaniel's concerns are misplaced. "Nested function calls" are not generally a problem. It is usually better to call a function from several places in your code than to inline the function. Why? Because the increase in code size causes more cache misses, and cache misses are *much* more expensive than executing the six or so instructions involved in a function call. Inlining is only a win for very small functions, and even then you have to be careful. Lots of C++ programmers, even those with exprience, tend to pointlessly inline things even though it's not providing any benefit.

Macros to rename functions would be handy.


ImaginaryHuman(Posted 2005) [#4]
You have a good point. There's lots of uses for macro's besides. You could have a macro containing only a few lines of key code that you happen to use a lot, and rather than having to cut and paste a lot you can just use a macro for it. It wouldn't have a huge impact on the cache. And some people would just prefer to work that way.

'To
Do
'it
   FOR People=NotTheWay to Go,
      Allowing=TheWay 'and
      Empowering=TheWay 'so
   Next
'time,
If YouWannaDecideSomeonesPathForThem Then LetGoAndLetBe() Else YouMightEndUp()
Loop'y
';-)



Rob Hutchinson(Posted 2005) [#5]
Just a note, Protean does not support "real" macros at the moment I'm afraid. Although you can assign basic chained actions to a mouse gesture. For example:

SBoxRowDelta(-1)
SBoxMoveToStartOfRow()
SBoxInsertText("bar",-1,-1)
SBoxColumnDelta(-3)
SBoxInsertText("foo",-1,-1)
SBoxScrollIntoView()
Which will move to the first column of the row above the one the cursor is on and insert "foobar", then scroll the line the cursor is on into view. Bit simple, but it works quite well for text inserts, there's also a load of other macros commands (somewhere approaching 100), that do all kinds of things, like opening files, find and replace, print, etc.

It doesn't have any kind of real logic or arithmetic though, it's just a list of simple commands,.. This will be fielded by the full .NET scripting engine (which was about 70% complete before I got caught up in BlitzMax stuff, and I plan to revisit that as soon as the BMX stuff is up to scratch).


Warren(Posted 2005) [#6]
Any chance of a Mac version, Rob? :)


Hotcakes(Posted 2005) [#7]
Once they release Windows for Mac, I'm guessing ;]


Mark Tiffany(Posted 2005) [#8]
Or .net for the Mac.


FlameDuck(Posted 2005) [#9]
It's all very well abstracting things and making it higher level but there is a speed expense.
True, but the performance hit is not worth considering on a pipelined CPU.


ImaginaryHuman(Posted 2005) [#10]
To me it's ALWAYS worth considering, maybe I am fixed in my ways :-o


Kanati(Posted 2005) [#11]
I've found that ASM programmers, as a rule, think just like you do. :)

I was there back in the 65xx days so I know. But now... not so much. :)


jhague(Posted 2005) [#12]
AngelDaniel, the point FlameDuck is trying to get across is that it is very difficult to figure out what's fast and what's slow on modern CPUs. Fewer instructions is not necessarily faster. It all depends on the mix of instructions, and that's something that is difficult to figure out with everything being executed out of order and registers being renamed on the fly and so on. What ends up mattering the most are cache misses, and even that can be dodgy to fully nail down. So you may think you'e optimizing when in fact you're not. Ugly-looking code might really execute like lightning.


ImaginaryHuman(Posted 2005) [#13]
My point is, I have this person over here *points* saying that these little odds and ends don't matter because it's negligible, then this other person over here *points* saying this doesn't need optimizing because it's not critical, then this other person *that one* saying the instructions will just disappear in the pipeline, so the picture I'm getting is that there are lots of areas where you could, individually, brush over things, but it does all add up, and it does depend on how many times you are going to be calling said routines.


Hotcakes(Posted 2005) [#14]
See, now, I got the exact opposite impression from all that than you did ;]

Or .net for the Mac.

Already done. Good for games.


jhague(Posted 2005) [#15]
AngelDaniel, if you really, truly, honestly need every last cycle like you claim, then Blitz is probably not the way to get that level of performance. If you look at the generated code, it's good, but not great. I fully expect that a good C compiler (like Intel's or Microsoft's for Windows), is going to beat BM by a factor of two.


ImaginaryHuman(Posted 2005) [#16]
Well, I don't need EVERY cycle but it'd be nice to get things to work efficiently rather than just sloppily, hoping there's enough cpu power to make sloppy code appear to run fast. I just like to code with an eye to optimal operating, don't you?


John Pickford(Posted 2005) [#17]
Optimise your algorithm NOT your code. Let the compiler worry about code optimisation.

You can optimise the code for a bubble sort as much as you like but there are other techniques that are fundamentally faster.

I came to this philosophy after many years of assembler programming. I've counted clock-cycles, unrolled loops, self-modified code, used un-documented opcodes and switched instruction order in my time. Ultimately, on modern hardware at least, it's pointless excercise. The time is bettter spent looking at your overall program flow and algorithms.


ImaginaryHuman(Posted 2005) [#18]
I prefer to do both, but thanks


Abomination(Posted 2006) [#19]
Time to Refresh this thread.
Apart from optimizing code...
Macro's can be a lifesaver when it comes to readability of your code.

--------------------
a=peekint(database,xpos+width*Ypos)
Using a macro like:
MakeMacro Getitem(peekint (database,xpos+width*Ypos))
that would become:
a=Macro Getitem
or even:
a=Getitem
----------------------
or:
----------------------
If A<Backup then A=C*Backup+SaveCount
If B<Backup then B=D*Backup+SaveCount
Using a Macro like:
MakeMacro SaveCheck(If {2}<Backup then {2}={1}*Backup+SaveCount)
one would get:
Macro SaveCheck({C},{A})
Macro SaveCheck({D},{B})
or even:
SaveCheck({C},{A})
SaveCheck({D},{B})
---------------------
[edit]
Since Macro's just replace texts one could do something silly like:
--------------------
MakeMacro UnScramble(Print {2}{1})
then,
UnScramble({o World"},{"Hell})
would result in:
Hello World
--------------------

I have found ThirdPartyEditors for other languages (including BB) that make use of Macro's, but not yet for BMax.
I wonder why, because its seems simple to implement in the IDE.


Abomination(Posted 2012) [#20]
Abomination goes 'BUMP' into the night.
Is there a BM-editor out there that can use Macros?
7 years and still nothing?
(cross my little heart)


Yasha(Posted 2012) [#21]
As long as the language doesn't support macros as part of the definition, there's not much point in editor support. Besides, editor support for "real" macros is actually really hard to implement efficiently, as it makes the editor have to do an unpredictable amount of work in between user inputs. Most C/++ editors don't really support macros properly either, and those languages have them formally integrated!

Since macros involve syntax modification (in retort to the thread above: using macros for "optimization" is Doing It WrongTM - the compiler is the only thing that should be handling inlining and other optimizations), you could even make a coherent argument that editor support is pointless: anything you "should" be doing with macros is something the editor should be fundamentally unable to identify.

So why not just modify BMK to run an existing macro system like the C preprocessor ("gcc -E"), minimac (seems similar to what you want), or something else? (or for that matter, even just apply it to your code manually before compiling.) Using macros with BlitzMax isn't hard.

Last edited 2012


ImaginaryHuman(Posted 2012) [#22]
I don't entirely agree, there is a place for macros and it can help as a form of short-hand to not have to write swathes of code when you know you can just inject code snippets where they're useful, without function-call overhead. But that overhead is probably not noticeable unless you're doing thousands of them, so maybe just use functions instead as a workaround?


Yasha(Posted 2012) [#23]
If the code in question can be expressed as a function, and half-decent compiler should be able to inline it as required, and will do a better job than the programmer at determining when function call cost is more or less important than code size. Macros really come into their own for reshaping syntax in ways that go beyond the simple function call model.

As far as I'm aware BlitzMax doesn't do inlining... if this is true, I consider it a bug. There's no excuse for not being able to inline "small functions" and single-use procedures, and even for medium-complexity functions the relevant theory is pretty well understood.

Functions are supposed to be a level of abstraction, removing specifics to make more generic algorithms. If you have to waste time thinking about the implementation of function calls at the machine level, the abstraction has failed in just about the most spectacular way possible.

Last edited 2012


Abomination(Posted 2012) [#24]
I am a lazy man. So I would like the IDE to tend to the tedious bits.
The examples I gave in that ancient post, are just 'one-line-macros' that
only require the IDE to cut and past a few words into a fresh line of
decent code. That should not lead to an unpredictable amount of work.
Of course it would get more complicated, if macros were aloud to loop or call upon other macros, but the control of the depth of such 'constructions' should not be that hard to maintain.
One could argue that 'basic' is a collection of macros for a machine-language.
(but I don't because I don't like to argue)
(well I do, but I am not very good at it.)
edit: an example of some recent code of frustrating ugly-ness;)

Using a Macro like MakeMacro ArrayPos([{1} Shr 16][{1}&PoolEnd])
It could look like:

Or by adding:
MakeMacro NextArray(Nex[{1} Shr 16][{1}&PooEnd])
MakeMacro PrevArray(Prev[{1} Shr 16][{1}&PooEnd])
It could look like:


Last edited 2012


Yasha(Posted 2012) [#25]
So is this something you think should be handled by the IDE, or by BMK?

Handling it in the IDE has the advantage of portability - what you save is pure BlitzMax code that can compile anywhere. But it kinda reduces the value of macros, since if the saved file contains the expanded forms, the macros won't exist next time you open it. This means macros become little more than typing shortcuts, and have no real value for code maintenance (a change in one place automatically rolling out to cover all points of use).

Handling it in BMK via a preprocessing pass means that only users with a modified BMK, or who are willing to run the macro processor by hand (really not a big deal) will be able to compile the code, but you retain many more advantages for editing and future maintenance, as the macro stays unexpanded in the code - I would have thought these are the important ones.

Using the CPP was a stupid suggestion, as I forgot it will choke on BlitzMax comments (the ' is used in C to open and close character constants). However, minimac might still be a reasonable one to consider adding as an extra precompilation step. It uses the backtick as a control character, which shouldn't conflict with BlitzMax code.


ziggy(Posted 2012) [#26]
I did write a sort of "templates" thing for Monkey that could be addapted to BlitzMax easilly and allows you to create macros-like documents that are embeded into regular source code between some comment marks in a way that if you modify the template files, you can apply the changes back to the original source code. Not ideal, but it works. I've been using it for my Harpl compiler, source can be taken from http://code.google.com/p/harpl-project/source/checkout

EDIT: This is the template parser source (it's Monkey but it's almost convertible to BlitzMax with very little changes): http://code.google.com/p/harpl-project/source/browse/MonkeyTemplateParser/template_parser.monkey

Last edited 2012


Abomination(Posted 2012) [#27]
So is this something you think should be handled by the IDE, or by BMK?

The more logical and 'therefore' more elegant solution, is to have both handle this.
The IDE could recognize the Macro-statements, copy and paste as needed and
'fold-away' the expanded code from the users view.
BMK than 'only' has to overlook the Macro-statements and just carry on with the expanded code.
Another (simpler) idea could be: to have the IDE save 2 source-files.
One with the macro-statement (.mbmx?), witch it can open instead of a .bmx.
And a file with just the expanded code to be handled by BMK. (.bmx!)

Last edited 2012