ID:1707641
 
Keywords: dm, efficiency
Hi, in university we started learning about how to code efficiently. So I have some questions about DM

1.How are variables implemented I mean they are all var type, does it work like python and implicitly decides the what type is variable?

2.Are all vars considered auto variables or can we use static/register explicitly (I'm talking about storage classes like the ones used in C++)

3.And how can global variables be read from all files without use of extern?

4.Are there some notes about what we should avoid doing in DM to use less CPU? Some rules that apply specifically for DM.
eg
Code:
for(var/i=1; i<=10000; i++){world<<"Hi!"} //I know 10000 is an exaggeration
instead of
proc Hi()
world<<"Hi"
for(var/i=1; i<=10000; i++){Hi();}


Is it all taken care of by DM?

About multi-threading and using x64 bit architecture I've allready asked.
Sorry if my questions sound naive to some programmers :)
1.How are variables implemented I mean they are all var type, does it work like python and implicitly decides the what type is variable?

For the most part, yes, variables do not need to be strongly-typed (that is, have their type explicitly defined). However, if you wish to access a member of a 'class', which in BYOND is simply referred to as a 'type', then you need to define the type with the variable declaration, f.e.:

var/item = new /obj/item(src.loc)
item.awesome = TRUE // Generates an error

var/obj/item/I = new /obj/item(src.loc)
I.awesome = TRUE // Valid DM


2.Are all vars considered auto variables or can we use static/register explicitly (I'm talking about storage classes like the ones used in C++)

See above.

3.And how can global variables be read from all files without use of extern?

Through the use of the .dme file, which serves to link all .dm files together in compile-time.

4.Are there some notes about what we should avoid doing in DM to use less CPU? Some rules that apply specifically for DM.

Some things that are important to consider when programming in DM: it's going to be several magnitudes slower than anything you'd get programming directly in C++, or any other relatively high-level language out there.

My biggest tip is to recycle objects. Probably one of the most CPU intensive things you can do is construct and destruct objects. If you have an instance where you are creating and destroying a lot of them, simply create a queue where objects go when they're not being used.


In the example you posted above, directly calling logic instead of separating iterated logic into its own function is the best way to do it. You are adding an extra 10,000 (roughly) operations that the Virtual Machine has to process. This turns out to have a huge difference when optimizing excessively-large loops.
In response to Doohl
Doohl wrote:
My biggest tip is to recycle objects. Probably one of the most CPU intensive things you can do is construct and destruct objects. If you have an instance where you are creating and destroying a lot of them, simply create a queue where objects go when they're not being used.

OOOO
DO THIS ONE LUMMOX.
An SS13 server has made their own version of this and it's worked amazingly well for most of their needs. Performance has been great too.


In response to Laser50
Dude BYOND already has a garbage collector. It's been around for ages.
Yes, another thing to note is that BYOND handles all garbage collection for you. This does not mean, however, that it will recycle objects as I described.
In response to Laser50
You could always use my queues if you ever wanted to implement that.
In response to MisterPerson
MisterPerson wrote:
Dude BYOND already has a garbage collector. It's been around for ages.

He means to reuse objects already created, rather than to create and delete objects over and over again.
In response to Lavitiz
Lavitiz wrote:
MisterPerson wrote:
Dude BYOND already has a garbage collector. It's been around for ages.

He means to reuse objects already created, rather than to create and delete objects over and over again.

I was talking to Laser50 who seemed to be under the impression BYOND didn't have a garbage collector. Pooling objects is a solid idea.
Ter13 has a nice library to handle object pooling:
http://www.byond.com/developer/Ter13/ObjectPools

And its accompanying documentation:
http://www.byond.com/forum/?post=1377691&forum=20
Thanks for answering, I've experienced the new/delete problem myself, but I believe the performance penalty is nothing compared to how many thing byond handles for us. I mean in C++ half my time goes on creating header files.
It may be more efficient to avoid unnecessary procedure calls, but doing so can make the code you are writing appear more "monolithic" and less modular.

While this isn't a good example, sometimes it can help to avoid this problem by invoking the preprocessor:
#define SayHi world<<"Hi!"

for(var/i in 1 to 10000) SayHi()// Yes, this is valid syntax in DM!

For the most part, you can go around pretending that SayHi() is a real procedure, but in this case I would suggest that you don't.

What I did with that for() loop is an undocumented use of the in operator. For more information on this, and other undocumented features, see:
The Red Book
In response to Doohl
Doohl wrote:
For the most part, yes, variables do not need to be strongly-typed (that is, have their type explicitly defined). However, if you wish to access a member of a 'class', which in BYOND is simply referred to as a 'type', then you need to define the type with the variable declaration, f.e.:

 var/item = new /obj/item(src.loc)
item.awesome = TRUE // Generates an error

var/obj/item/I = new /obj/item(src.loc)
I.awesome = TRUE // Valid DM


You don't always have to do this. Sometimes you will run into cases where you don't know what type of variable you are dealing with. In that case, you can check for it at runtime:
var/item = new /obj/item(src.loc)
if(istype(item, /obj/item))
item:awesome = TRUE // This is also valid in DM.

However, you have to be more careful when doing this, because the compiler isn't going to be holding your hand.
In response to Multiverse7
I'm well aware of this, but it's generally not a good practice to use the : operator, in my opinion. It's always much, much safer to typecast. And I've never really run into a scenario where using a direct member accessor was better than just typecasting.

The only thing I can think of is if you are trying to avoid using istype() too many times, because it actually can hog your CPU time if you use it many times in a loop or what have you.
In response to Doohl
Doohl wrote:
it's generally not a good practice to use the : operator

It's only not a good practice if you don't know what you are doing.

It's always much, much safer to typecast.

Code is only ever going to be as safe as you can write it. I don't write code so that I can feel "safe", especially if it sacrifices any useful functionality.

And I've never really run into a scenario where using a direct member accessor was better than just typecasting.

The way I program, most of my world is generated at runtime, so it helps to be able to manipulate different types of objects in different ways, but with a flexible, uniform interface.

The only thing I can think of is if you are trying to avoid using istype() too many times, because it actually can hog your CPU time if you use it many times in a loop or what have you.

That's somewhat understandable, but then I would find ways to more efficiently predict the type of object that I'm dealing with.

Variables are variable, and if I don't acknowledge that, then I'm probably doing something wrong.
In response to Multiverse7
Let's agree to say that we adhere to different styles of programming :P

If you want to know what direction this discussion will probably go in, google 'using goto'. One side says it's okay to use goto if you "know what you're doing", the other side says it's completely wrong to use goto in any situation.
Say no to goto.
In response to Doohl
There is no comparison between the : operator and the archaic, redundant goto function. A project full of gotos can be terrifying. I will avoid anything involving goto at all cost.

The : operator is nothing like goto. Its usage is simple and straightforward. If you get an error, you can actually find out where it came from and why it happened, unlike with goto.
In response to Doohl
IMO: In general, you should never assume that you (or especially, anyone else looking at your code, because that happens in the real world) know what you're doing, and you should always expect to overlook something; especially after time away from the code.
In response to Multiverse7
Multiverse7 wrote:
The : operator is nothing like goto. Its usage is simple and straightforward. If you get an error, you can actually find out where it came from and why it happened, unlike with goto.
The point of using the colon operator is to suppress compiler errors. You may still get runtime errors (due to refactoring or something), but it's better to have compiler errors than runtime errors because then your clients/testers don't get to complain that your thing is broken.
In response to Kaiochao
There are safety checks you can use to suppress even the runtime errors if needed, so that things fail "silently", unless you are debugging the program.

Either way, there's nothing wrong with getting runtime errors. They are there to help you.
Page: 1 2