Extrema

by Pirion
This library creates a container that allows you to store a single value within minimum and maximum constants.
ID:1639389
 
The extrema are the minimum and maximum values of a function. This library creates a container that allows you to store a single value within these constants.

The library also provides some convenience functions that provides general functionality.
Why not just do this?

mob
var
// Health
minHealth = 0
maxHealth = 20
health = 20

// Mana
minMana = 0
maxMana = 10
mana = 10
When doing this, you'll need to write a function to handle ensuring each variable is within bounds. This requires changes and testing each time.

mob/proc/HealthToValue(amount)
amount = max(minHealth , amount)
amount = min(maxHealth , amount)
mana = amount

mob/proc/ManaToValue(amount)
amount = max(minMana , amount)
amount = min(maxMana , amount)
mana = amount


Using a datum encapsulates this behavior allowing you to test once and reuse many times.

i.e.
Health.ToValue(amount)
Mana.ToValue(amount)



This is the general design advantage of object oriented programming - in which the language was built around.
Seems verbose and a waste of resources. Just because something can be turned into an object doesn't mean it should be an object.

Those two procs you posted, I don't even know what you think they do.

mob
proc
damage(amount)
health -= amount
if(health < minHealth)
health = minHealth
death()
It is not. This object can be created for many scenarios and used every time without needing to write more code than defining the object.

Code Once, Reuse Everywhere is a fundamental.

Hopefully, You'll learn this sometime. The alternative leads to copy and paste coding and leaves room for update anomalies.
In response to Pirion
*chuckles* Maybe one day you'll learn how over engineered and unhelpful this really is for making a game.

Extrema I'm sure has it's uses elsewhere, but not here. You're making a small aspect of a game far more computationally expensive than it needs to be.

Fact is, if you wrote code that uses this I could write code that does what yours does only faster by skipping the nonsense.

An object is made of data and methods for manipulating that data. The methods for manipulating integers is already there. They're called + - * / %

No need to reinvent the wheel.
Look, here's the proof. Using your code is 4 times slower.

The test:
mob/verb/testExtrema()

for(var/i = 0 to 100000)
SetHealthToMax()
SetHealthToMin()
SetHealthToOne()
SetHealthToX(900)


var/mana = 1000
var/maxMana = 1000
var/minMana = 0

mob/verb/testNormal()

for(var/i = 0 to 100000)
mana = maxMana
mana = minMana
mana = 1
mana = 900


The results:

Your code does not provide the same functionally. If I had four assignment calls, I would be much better off too. Granted, I was not as green as I could've been. Needless to say however, when used in the same way as my library your code produces buggy results and is higher maintenance.

We're splitting hairs on an old argument - do you write code that performs high with bugs, or write code that still performs well without bugs?


Either way, I will use my library as I follow the concept of writing code bug free. If you don't, no harm done.
For a game performance is essential. If you're creating a ton of functions for menial tasks you're adding a massive overhead to your game in the long run.

Performance is especially essential for such an old platform like BYOND where you really have to juice it for all it's worth.

If you look at code I've written and posted they always follow a strict OOP design but creating objects and method calls that just simply don't need their own object and methods.. It's asking for lag.
If you create duplicate behavior in your code, you're setting yourself up for failure.

If you won't take advantage of the language due to too much pre-optimization, you're making it much harder on yourself. Write code, find your bottlenecks, and then focus on them. 100000 calls and we're not even looking at half a second. My point here is this; when it takes this much to get a reading and won't be used this way in the actual game does it really matter?

Finally, what I've placed in this library is nothing new. It goes back to a Dream Tutor article posted many years ago, explaining when exactly to use datums. It is a fundamental concept of object oriented programming.

Dream Tutor: Datums Are Our Friends
One issue I have is how splintered the files are in their organization.
There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies.
There are two types of people in this world: people that believe datums are our friends, and those that don't.
In response to Zecronious
Zecronious wrote:
Look, here's the proof. Using your code is 4 times slower.

The test:
> mob/verb/testExtrema()
>
> for(var/i = 0 to 100000)
> SetHealthToMax()
> SetHealthToMin()
> SetHealthToOne()
> SetHealthToX(900)
>
>
> var/mana = 1000
> var/maxMana = 1000
> var/minMana = 0
>
> mob/verb/testNormal()
>
> for(var/i = 0 to 100000)
> mana = maxMana
> mana = minMana
> mana = 1
> mana = 900
>

The results:


You're benchmarking wrong. What you're looking at is how long it took SetHealthToX to execute 100001 times in total. Divide 0.388 by 100001 and you see that it takes 0.00000387996 seconds.

In response to ExPixel
Owned
DEMOS ARE MY THRIGGER OMG!!!!!!!!!!!!!!!!!!!!!!!
In response to ExPixel
ExPixel wrote:
You're benchmarking wrong. What you're looking at is how long it took SetHealthToX to execute 100001 times in total. Divide 0.388 by 100001 and you see that it takes 0.00000387996 seconds.

He didn't benchmark it wrong, he worded his claim wrong. What you stated was the average of one procedure, which isn't the same as how it performed as a whole. When put into context that the for loop and the initial stack play constituent in the performance the wording of his calculations is slightly off... but there's no reason for procedure delegation to be faster, and it's not...

Calling procedures in BYOND is very slow when compared to other languages and it's managed horribly with no optimizations whatsoever. That's why it's crucial to get as much of a speed boost as possible when working in it... which is ironic. Higher level languages should be optimized to offer convenience on the programmer.

If he worded it "Your code used in this context would amount it to be 4 times slower in comparison to raw statements." Then he'd have been correct. I'd wager it's still considerably slower regardless. If Piron's system was made in MACROs, or ported to C++ using inlines, or even ported to Java then it'd be somewhat ideal... but not in BYOND.
I'd just like to say something.

We're measuring these things in thousands of a second, if not more, like tens of or even hundreds of thousands of a second.

Realistically, we'll probably never see a BYOND game where this level of efficiency is ever an issue.
Honestly, that is what my thought was.

I've switched some of the checks up to bypass calls and reduce some redundant calls - which for me has put the real-time a little over a second for 40k calls. If I see anything else I can reduce, I will.
In response to The Magic Man
The Magic Man wrote:
Realistically, we'll probably never see a BYOND game where this level of efficiency is ever an issue.

If the game gets popular, it sure as hell will. As little as 350 default movement calls at 10fps half way maxes out a 3.5ghz thread, and since BYOND's single threaded that could impose a big issue for a lot of games.

That strays a little out of context, but the efficiency here by example is by no means contrived. It becomes exponentially noticeable with the amount of players and other procedures trying to be called on the stack.
Page: 1 2