Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blit::random() cannot be used in global initializers (except on device) #484

Open
a2 opened this issue Dec 23, 2020 · 8 comments
Open

blit::random() cannot be used in global initializers (except on device) #484

a2 opened this issue Dec 23, 2020 · 8 comments

Comments

@a2
Copy link
Contributor

a2 commented Dec 23, 2020

If I want to store a random number that's globally initialized, I can't do that with blit::random() until init() is called. This works on a 32blit device though, which I think is because api is initialized differently there.

const uint32_t _test = blit::random();

This can be worked around by removing the const modifier and assigning in init(). However, it becomes more complicated when blit::random() is used in other parts of the code:

class Flower {
  public:
    Flower() : height(blit::random()) {};
    const uint32_t height;
};

Flower flower;

Right now my interim solution is to use a pointer like so, and initializing Flower later in init():

Flower *flower;
@Daft-Freak
Copy link
Collaborator

Yeah, I've hit this one before, not sure there's actually a way to fix this...

The only reason this works on device is because the API is initialised before the game even exists. (API is setup by the firmware. which then starts loading the game, for SDL the constructors have already happened before we can do anything.)

@Gadgetoid
Copy link
Contributor

I’m not totally averse to quietly “ifdef”ing this issue under the rug. I don’t think there’s any other way it could be fixed?

The whole concept of the API is a little contrived for SDL, where there’s no real separation between the “HAL” and game. It feels like it should not be intrinsic to the “engine” but constitutes something that’s really neither “engine” nor “HAL”. Maybe these a fundamental architectural issue behind this bug?

@Daft-Freak
Copy link
Collaborator

Daft-Freak commented Dec 30, 2020

Hmm, an idea: add a API_FUNC macro

//SDL
#define API_FUNC(name) name
//STM32
#define API_FUNC(name) (*name)

Then all the API functions could be implemented for SDL as

uint32_t  API::random()
{
...
}

Going even further, they could all be regular function declarations, implemented by either 32blit-sdl32, or a new 32blit-stm32-user library (that just forwards trough the API section). Though that would end up with some stuff having multiple levels of wrapper...

(I think these were function pointers even before the API stuff, so it's always had this issue... It just got accidentally fixed on device by the user/firmware split)

@Daft-Freak
Copy link
Collaborator

Hmm, first idea is not so bad master...Daft-Freak:sdl-no-ptrs (needs some indent/namespace tidying)

I had an attempt at going further which... did not go so well.

@Gadgetoid
Copy link
Contributor

Found out that this also applies to things like "screen.bounds.w" which are all too easy to assume would "just work" if you use them inside - for example- a class constructor. However - Since we can't know the screen resolution ahead of time (it's potentially changed in init) this might have to just be a "don't do that" learning experience that we document somewhere. May be other cases of this too?

@Daft-Freak
Copy link
Collaborator

screen is possibly the only one that makes sense... since set_screen_mode is pretty much screen = [hi/lo]res_screen.

(Although, since there's no guarantee on the order of global constructors across files, you should really avoid using anything you didn't declare in them...)

@Daft-Freak
Copy link
Collaborator

Hmm, thinking about the original issue more...

The SDL version of blit::random uses a global random_generator, so even if there was no API function pointer stuff going on, calling it from a global constructor would be "undefined". (Your constructor could happen before random_generator's)

@Gadgetoid
Copy link
Contributor

In this case should we document a "don't do this" and suggest people initialize things they want to be random at runtime? I don't think it's super wrong to accept and document compromises.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants