Macros?

BlitzMax Forums/BlitzMax Beginners Area/Macros?

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?

Thumbs up - I used these on the Amiga version of Blitz.

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.

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
';-)


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).

Any chance of a Mac version, Rob? :)

Once they release Windows for Mac, I'm guessing ;]

Or .net for the Mac.

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.

To me it's ALWAYS worth considering, maybe I am fixed in my ways :-o

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. :)

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.

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.

See, now, I got the exact opposite impression from all that than you did ;]

Or .net for the Mac.

Already done. Good for games.

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.

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?

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.

I prefer to do both, but thanks

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.