This was originally going to be a reply in my "Why OOP?" topic, talking about efficiency in loops, but I decided to make it a whole topic on its own.
One interesting way to make a pretense of using procedures when in reality doing no such thing is to use macros
#macro MOVE_PARTICLE_TO(particle, x, y)
particle._x = x
particle._y = y
#endmacro
Type pticle
As Integer _x, _y
End Type
Dim As pticle myparticle
MOVE_PARTICLE_TO(myparticle, 0, 0)
Print myparticle._x
Print myparticle._y
MOVE_PARTICLE_TO(myparticle, 23, 42)
Print myparticle._x
Print myparticle._y
Sleep
This can be used in loops without slowing things down, since it's not really a function call at all. The one downside is that you don't have type checking, meaning you could do really weird things like
MOVE_PARTICLE_TO("this is a string, not a particle!!!", "hi, guys!", "this is a totally invalid place to move the particle to! it's not even a number!")
where you pass arguments that are the wrong type and get weird errors for seemingly innocent lines of code. Even worse, the first argument to the macro can be any type that has public members _x and _y - so for example, I could do
Type myrandomthing
As String _x, _y
End Type
Dim As myrandomthing someObj
MOVE_PARTICLE_TO(someObj, "Hello, ", "World!")
Print someObj._x
Print someObj._y
Sleep
and it will compile just fine despite the fact that the object and parameters to the macro have nothing to do with particles or even positions. Such is the facts of life when using the preprocessor, which does nothing more than a simple string replace and converts the above code to:
Type myrandomthing
As String _x, _y
End Type
Dim As myrandomthing someObj
someObj._x = "Hello, "
someObj._y = "World!"
Print someObj._x
Print someObj._y
Sleep
which is of course perfectly valid, if odd, code.
Despite the weirdness, macros do have their uses, and keeping things fast (while somewhat clean-looking, as long as you're careful with it) could be one of them.