Crystal: Documentation for extended modules

Created on 18 Nov 2019  路  5Comments  路  Source: crystal-lang/crystal

When a type extends a module, the doc generator lists the module under Extended Modules, but no methods are listed, which means you need to follow the link to the extended module to see which methods would be available.

An example for this is Random::Secure which extend Random and extend self (see next paragraph about that). The documentation only shows two methods: #next_u and #random_bytes. These are only low level methods, and the entire rest of the API (i.e. the important parts like #rand) is completely missing.
I think we should fine some way to show methods from extended modules.

A special case is extend self which leads to the extended methods being displayed in the module, but only as instance methods. It is not clear that these can actually be called as class methods.
I'm actually not sure about the overall usefulness of extend self. AFAIK, it is mostly just used for declaring class methods as instance methods, which essentially just saves a few self. receivers for the method definitions. Defining these methods as instance methods is deceiving though, when they're not actually meant to be used as such. For example Benchmark, Math or FileUtils methods won't ever be used as instance methods. So maybe I'm making a side-case for removing extend self here, but the main point is improving documentation. A valid improvement for these modules would probably be to remove extend self and directly use class methods instead.

docs feature discussion topicdocs-generator

Most helpful comment

Moving a bit forward in that direction: i'd like to completely remove extend, not just extend self

All 5 comments

Moving a bit forward in that direction: i'd like to completely remove extend, not just extend self

@asterite As a matter of fact, most extends in stdlib are actually extend self. Only Env, IO::ByteFormat::{Big,Little}Endian and Random::Secure extend some other module. System::{User,Group} extend the internal system modules.

Math and FileUtils are perfect example of why extend self is nice to have: we can call a few of their methods directly on the module here and there but can also include them and call their methods directly, which is very useful to write script like programs without the noise of prefixing each and every call (or having to write lots of instance to class delegator methods).

I usually avoid extend self just to skip def self., but I use it regularly for helper modules in Ruby.

Same in stdlib: they're here for reason, not just to skip some def self.

@ysbaddaden Yes, making the methods available in another scope is a valid use case. But the means to achieve this through extend self seems not an ideal solution.

Even if you want to include the methods from say Math into another scope, none of them is actually an instance method. Yet they're defined as instance methods because that's required for extend self and including them in another scope.

Optimally, they should simply be class methods. And then there could be a language feature to make a module's class methods available in another scope.

This would solve the use case perfectly without being weird.

If a class B inherits a class A and A has class methods, a section "class methods inherited from A" will list those methods.

I think we just need to add a "class methods inherited from M" if A extends M.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ArthurZ picture ArthurZ  路  3Comments

jhass picture jhass  路  3Comments

pbrusco picture pbrusco  路  3Comments

Sija picture Sija  路  3Comments

cjgajard picture cjgajard  路  3Comments