Is $ the same as 'default'?

iktian

New Member
Mar 24, 2019
4
0
I know define should/can not be used as a dynamic variable, but in scripts of some games I'm noticing they initialize flags using both $ and default. In Eternum's script particularly I'm noticing booleans are set using default [default annie_path = True], and ints/strings are set with $ [$ annie_points = 0].
Is this just a personal preference or a functional difference?
 

GetOutOfMyLab

Conversation Conqueror
Modder
Aug 13, 2021
7,823
21,835
I know define should/can not be used as a dynamic variable, but in scripts of some games I'm noticing they initialize flags using both $ and default. In Eternum's script particularly I'm noticing booleans are set using default [default annie_path = True], and ints/strings are set with $ [$ annie_points = 0].
Is this just a personal preference or a functional difference?
Explained very well here:
 

iktian

New Member
Mar 24, 2019
4
0
Explained very well here:
I already read this one, I'm just confused about the technicality since both the defaults and $ statements are defined on init generally. I guess there wouldn't be a difference between the 2 in that case.
 

GetOutOfMyLab

Conversation Conqueror
Modder
Aug 13, 2021
7,823
21,835
I already read this one, I'm just confused about the technicality since both the defaults and $ statements are defined on init generally. I guess there wouldn't be a difference between the 2 in that case.
You can potentially have save errors if you simply use $ to set the initial variable value. We see this often in games where you load an old save, but they added a new variable earlier in the script using this method. Then, when you reach a point where that new variable is used, it gives an error.

default should be used for variables that change during game play.
 
  • Like
Reactions: iktian

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
5,675
8,298
I already read this one, I'm just confused about the technicality since both the defaults and $ statements are defined on init generally. I guess there wouldn't be a difference between the 2 in that case.
Default = Variable
Define = Constant


Define pi = 3.1f
Because pi will always be that value, it's not a variable, but a constant, so you use define.

Default money = 0
Money will keep changing during the game, it's a variable, so you use default.

$ = Calling python stuff, outside of ren'py.

You keep default and define outside of init, or any method at all. You can keep them in a .rpy file.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,627
2,286
Is $ the same as 'default'?

Nope. Not even close.

Is this just a personal preference or a functional difference?

Some older games tend to initialize variables using $. Usually within an (initialization block).
default was added to RenPy later, and is why those older games didn't use it.
The problem being that later developers then copied that older code into more recent games. Good games don't always mean good programming. As a result, a lot of bad habits persist into modern RenPy games.

as already stated is pretty much "do single python command."
More importantly it is pretty much "do that single python command now."
As part of an init block, those commands (initializing the variables) ran during game startup.

Less commonly back then, developers would put those same commands in the main body of their script. Usually just after the label start. No harm done. The game would start, and the variables would be initialized (either in the main script or within the init block).

The problem is the developers add, remove or change the use of variables as they continue to develop their game.

Imagine a developer adds a new variable (mynewvar) as part of their episode 3 release, but related to code that happened in episode 1.
The logical place to initialize that variable would be with all the other ep1 variables (probably at either label start or the episode 1 script).
Except, you have players out there who are in the end of episode 2. Their save files don't include that variable, because it wasn't added until later. They haven't restarted the game or replayed episode 1, so the $ code hasn't been run.
The player loads their ep2 save and starts to play through ep3 and encounters an if mynewvar >= 1 statement. The game crashes, because as far as the game is concerned, that variable doesn't exist (critically, it wasn't loaded from the save file and the value hasn't changed since).

This was why default was added to RenPy.

It is a mechanism that initializes variables regardless of where in the code the default statement is placed. Most critically, it protects programmers from falling for this edge case bug for variables added to the script later. If the developer uses default, they'll never need to worry about whether the variable exists or not, because it always does.

If the script encounters a default statement while it is being executed - that statement is effectively ignored (because it's already been processed during game startup).

Want a really bad example?

Python:
label start:

    scene black with fade
    "*** START ***"

    "The variable value is [mynewvar]."

    $ mynewvar = 7

    default mynewvar = 99

    "The variable value is now [mynewvar]."
    "*** THE END ***"

    return

This works, because the default statement is executed during startup and not at run time.
It will print "99" and then "7".

As for the difference between default and define, others have already explained that default is for variables that change value while the script is running and define is for variables that don't (static variables).

It's probably worth explaining why.
(From my limited understanding): Anytime the value of a variable is changed during runtime execution of the script, there is some sort of flag for each variable to include that variable within the next save/autosave file. (think of it as "marked for saving").

define doesn't set that flag. default does.

So when a player loads a save file, they get all the latest values of those variables for that playthrough, without making the save file huge by saving variables that will never change.
It also means that a developer can change a variable created using define and the player will see that new value and not the value when the player was previous playing.
Imagine something like define maximum_lovepoints = 100 and the developer want so up that value to 120. If they'd used default, the player would load their save file and the value would be overwritten with 100. Not what the developer had in mind.
More commonly, it would be something more like changing the color of a character's name or something like that.

The explanation and reasoning why may be complicated, but the implementation is easy:

"use for variables that might change and for variables that almost never will".​
"init blocks are the 'old' way of doing it".​

Or put another way, "define is for constants and default is for variables".
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
11,423
17,387
I'm just confused about the technicality since both the defaults and $ statements are defined on init generally. I guess there wouldn't be a difference between the 2 in that case.
There's a major difference between the two.

Variables declared through default will always be included in a save file, while variables declared in an init block through $, or in an init python block, will only be included in a save file if their value have been changed.
The issue being that lists, dictionaries and objects do not change when they are updated.

It's variables declared through define that are, in their behavior, similar to variables declared in an init or init python block.


On the SDK, open the console and type this:
myVar = 1
id( myVar )
You'll get something like "485187408L" it's the variable ID, what permit to find it in the memory.

Now, type:
myVar = 2
id( myVar )
You'll see that the variable ID have changed.

But if you type this:
myVar = [ 1 ]
id( myVar )
myVar.append( 2 )
id( myVar )
The variable ID will stay the same before and after the update of the list.

And, as I implied above, the same apply to dictionaries:
myVar = { "a": 1 }
id( myVar )
myVar["b"] = 2
id( myVar )
myVar["a"] = 2
id( myVar )

and to objects:
myVar = renpy.python.RevertableObject()
id( myVar )
myVar.a = 1
id( myVar )
myVar.a = 2
id( myVar )

There's a whole thread regarding variables, including those differences.



On a side note, should be also noted that, I don't really remember when between the 7.5.x and 7.7.x, Ren'Py introduced the notion of " ".
It's more a design than anything else, since variables in a constant store can still be changed. But whatever if they are declared through define, default, in an init or init python block, or inline in a label through $, those variables will not be included in a save file.
/!\ Warning, they also don't participate in rollback. /!\




Oh, and Happy New Year to everyone.
 

Turning Tricks

Rendering Fantasies
Game Developer
Apr 9, 2022
1,519
2,807
I already read this one, I'm just confused about the technicality since both the defaults and $ statements are defined on init generally. I guess there wouldn't be a difference between the 2 in that case.
I highlighted the part I don't think anyone addressed yet.

$ preceded statements are not defined on Init. They will be set when that line of code is reached in the game loop, unless they are part of a block that is intended to be loaded at start-up and structured that way (init python) As mentioned several times already, using $ just means it's basically a 1-line python statement.

That's why we use them all the time to set and change variables. The default gets set at Init and then we can change them whenever we want. Often times, an error in one of your $ statements won't throw an error until the game loop comes to that point.
 
  • Like
Reactions: osanaiko

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,627
2,286
$ preceded statements are not defined on Init.

Not quite.

Reality is they used to be, sometimes. (mainly before the default statement was added to RenPy).
Even in some recent games, you occasionally still see it - because people assume a popular game is well written and copy code without understanding everything about it (which is fine, until it doesn't work as expected).

In much older games, you'd occasionally see something like:

Python:
init:

    $ alice_love = 0
    $ beth_love = 0
    $ carol_love = 0

label start:

    # etc.

Thankfully default has replaced this and the older style is slowing falling out of usage.
 
  • Like
Reactions: Turning Tricks

Turning Tricks

Rendering Fantasies
Game Developer
Apr 9, 2022
1,519
2,807
Not quite.

Reality is they used to be, sometimes. (mainly before the default statement was added to RenPy).
Even in some recent games, you occasionally still see it - because people assume a popular game is well written and copy code without understanding everything about it (which is fine, until it doesn't work as expected).

In much older games, you'd occasionally see something like:

Python:
init:

    $ alice_love = 0
    $ beth_love = 0
    $ carol_love = 0

label start:

    # etc.

Thankfully default has replaced this and the older style is slowing falling out of usage.
That's what I was trying to say, probably not well tho, lol.

Just that they used to be used in init blocks all the time. When they are just used inside the main game loop, then they don't get processed until that line is read. This makes it hard to troubleshoot code sometimes as Ren'py often won't throw an error until you reach that line. And iirc, LINT doesn't always catch it either. So if it's a variable being set on some obscure path in your game, that only a small percentage of players will ever reach, you can have a bug that goes unreported for ages. Heck, I only just last week fixed a bug from my Ver. 1.0 reboot that was released over a year ago, haha! And that's only because a player was messing around with that URM cheat and reported it. Sometimes those guys make the best free beta testers.