Conditional imports?

Currently import statements cannot be wrapped inside when statements. Is there a workaround to this? I don’t want to stop using -vet-unused-imports directive for the compiler.

I know about build tags and file suffixes, but is there a way they can be used with #config constants set with -define args?

If your concern is only errors from unused imports, you can declare them to _ to avoid that.

import "core:fmt"
_ :: fmt
// no error with -vet-unused-imports if fmt is never used

Otherwise, you can’t make the import itself conditional aside from build tags/file suffixes, which aren’t flexible for anything more than per-platform code selection. Generally, if you don’t use the contents of the package, it won’t end up in the final binary, so the import itself doesn’t actually need to be conditional.

This isn’t just “currently” but import statements will never be allowed within when statements. This is a lot more complicated than you might imagine and thus why it has been prevented.

Most of the time your imports should just be for that file only, and if you need platform specific code, use things like foo_windows.odin or bar_amd64.odin, or to use #+build tags.

As for -vet-unused-imports, there are three possible options to do:

  • _ :: fmt
    • this just shuts up -vet
  • @require import "core:fmt"
    • this is not just to shut up -vet but to make it clear that you want the @(init)/@(fini) procedures for that package
  • #+vet !unused-imports
1 Like

If you want to use a conditional import, #+build tags and magic suffixes are your only option, as gingerBill pointed out in the post above. This will work for platform-specific functionality, and if you wanted to use custom constants, you can wrap the contents of the imported file in a giant when statement.

So if I use the _ :: fmt thing and don’t use the package, it’ll ignore the @(init) functions of that package?

PS - what is @(fini), I couldn’t find it in docs.

The entry point procedure of Odin looks like the following:

  1. Initialize everything and call all @(init) procedures
  2. Call main()
  3. Definitialize everything and call all @(fini) procedures.

@(fini) is the opposite of @(init), it’s for executing code after main() has finished executing.

Does the _ :: fmt thing skip these calls if the pkg is not used?

In case anyone opens it looking for a different kind of workaround, I more or less hacked it in by using -collection: compiler option.

For different kind of builds, I pass in two different implementation folders. It’s a bit iffy with language server but so would be the conditional imports. And it works. :smiley:

No. Those calls are still called because it cannot know if you wanted to use it or not.

The difference between @(require) and _ :: fmt is purely aesthetic. @(require) exists for foreign import too, which makes it more consistent behaviour between import and foreign import.

1 Like

As someone who has to deal with python ecosystem I can add that conditional imports are pure evil. The behavior of the software magically changes when some condition you have never suspected to exist holds true. There is no good way to statically analyze such code and packaging becomes a nightmare.