Imports (require)

Is there a way in Crystal to import a class or method from a file with a given prefix (as if said objects (class, method, variable) were defined in a given Module)?

For instance, how could I invoque say mathematical functions (sin(), cos()) from an hypothetical external math file as math.sin() math.cos() rather than as bare sin(), cos(), in order to make it obvious that these methods are

  1. Imports.
  2. Moreover imports from a specific file named «math»

Of course, if I am the author of said « math » file, I can achieve this effect by further wrapping this library of external methods in a module with the same name, but what if I am not the author of said file, but still want « explicit » imports or explicit references to the imported file?

Is there a (possibly optional) syntax like « require myMath as math » or something similar in Crystal?

No Crystal doesn’t have anything like this. Ideally library authors would namespace their types/methods, e.g. https://crystal-lang.org/api/Math.html as opposed to just defining things on the top level that may conflict with other types/methods.

Also see Modules - Crystal.

1 Like

Thanks!

Is there perhaps a workaround with macros?

Workaround for what exactly?

A means to import (require), say, a method m1(), for instance, alternatively as:

  • m1()
    or as
  • myFile.m1()

regardless of modules, depending upon cases where conciseness is a priority or cases where clarity (explicit belonging of a function to a file) is considered a priority.

Example from Go:

import _ "foo"
import "fmt"

There’s no way to do that. On the other hand, most methods in a library are instance methods, so the times where you do need to call a module function are pretty rare.

1 Like

Thanks.

If you’re only talking about the Math module itself, that module already extends itself, so you can already call Math.sin(), Math.cos(), etc… That way you know those are methods on that module.

As for other modules, you do something similar depending on how you have things setup. Open the module, extend self, then when you require that module, you could call the methods from the module itself.

module Utility
  extend self

  def m1
    puts "do stuff"
  end
end

class Test
  def call
    Utility.m1
  end
end

Lastly, you can assign a constant to a variable like myFile = Utility, then call myFile.m1().

It’s not really common with Crystal to write this sort of code, but if you need to, there’s a few small possibilities.

2 Likes

Thanks.
But conversely, I assume I cannot require “math” and discard the Math prefix, all I can do is make it shorter, as in:

require "math"
m = Math
puts "cos(0) = #{m.cos(0)}"

But there in no built-in mechanism to call, say the cos method, without any prefix, _I guess?

You can do include Math, but that makes those methods available everywhere.

There was a proposal for private include but it never happened

1 Like

Thank you!

Crystal basically concatenates every file that are required (relative or absolute) together and compiles them. That’s not exactly true because global vars are still local to a file, but that’s why you can add only one “require” and have the methods available everywhere.

For a while it was annoying me. I would have liked requires to be mandatory in every file where a method of the required file is used, a bit like go. But now I don’t think that would be a good idea. The crystal way is simple, it is probably better to keep it like that, adding complexity is not needed.

2 Likes