# Base.modules\_warned\_for silently removed in 1.8

**URL:** <https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035>\
**Category:** General Usage\
**Tags:** breaking\
**Created:** [April 5, 2022, 7:17am UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035 "2022-04-05T07:17:53Z")\
**Posts on this page:** 20\
**Page:** 5

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [June 8, 2022, 1:38pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/81 "2022-06-08T13:38:11Z")

</div>

> [@Sukera](#):
>
> I don’t think so. Code review precisely means “checking whether the new code is up to the standards of the existing code base” (whatever your standards are).

I think it’s totally sureal to have to check each and every function in a PR to see if it’s documented/exported/in-the-manual/etc.

> [@Sukera](#):
>
> At the very least, you can require some third-party provided (i.e., not stored in the code) secret that cannot be read in by a malicious plugin and secure your API access that way, by authenticating any access to sensitive parts through that token.

Think of something like VSCode, Slack, etc - anything that can be extended by plugins and integrations and any module/plugin having access to any other module/plugin.

* * *

Anyway, I don’t think we can reach an agreement beyond this point as we’re literally going in circles. It’s been a good discussion and it’s good to have this here in the open. I appreciate all the input and respect all the opinions, even if they can’t be reconciled.

---

<div class="post-metadata">

**Author:** ![skleinbo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skleinbo/32/36080_2.png) [@skleinbo](https://discourse.julialang.org/u/skleinbo)\
**Post date:** [June 8, 2022, 1:43pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/82 "2022-06-08T13:43:33Z")

</div>

You are absolutely right. Maybe its ubiquitous use had lulled me into thinking it were part of the API.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [June 8, 2022, 1:50pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/83 "2022-06-08T13:50:35Z")

</div>

> [@essenciary](#):
>
> sureal to have to check each and every function in a PR to see if it’s documented/exported/in-the-manual/etc

Most modules follow the convention that exported symbols are public, so you would only have to check ones that were specifically imported or are accessed with `.`.

While I agree that some tooling would be nice for this, this is usually a small part of reviewing a PR, so apparently this is not a key issue for most people. For example, the [commit](https://github.com/GenieFramework/Genie.jl/commit/1980b485f4f8b74de33cf5db8eb48cae38888fc6) where you introduced this to Genie has added **4 lines of code**. Personally, I don’t find checking this much code _surreal_, YMMV.

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [June 8, 2022, 1:53pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/84 "2022-06-08T13:53:09Z")

</div>

> [@Tamas\_Papp](#):
>
> For example, the [commit](https://github.com/GenieFramework/Genie.jl/commit/1980b485f4f8b74de33cf5db8eb48cae38888fc6) where you introduced this to Genie has added **4 lines of code**. Personally, I don’t find checking this much code _surreal_, YMMV.

It’s a matter of principle and methodology.

---

<div class="post-metadata">

**Author:** ![skleinbo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skleinbo/32/36080_2.png) [@skleinbo](https://discourse.julialang.org/u/skleinbo)\
**Post date:** [June 8, 2022, 1:58pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/85 "2022-06-08T13:58:00Z")

</div>

That’s what I actually meant with documentation 🙂

Still, in this particular case, `@kwdef` is a) very useful and b) often utilized. Just by looking at other people’s code, one will likely discover it. The fact that it has a very nice docstring (with example!) could make one believe that it is save to use without checking the manual first. Of course one might argue in the case of breakage that the user neglected their due diligence, but I can’t help but feel that’s not entirely warranted either.

---

<div class="post-metadata">

**Author:** ![mbaz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbaz/32/17295_2.png) [@mbaz](https://discourse.julialang.org/u/mbaz)\
**Post date:** [June 8, 2022, 2:15pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/86 "2022-06-08T14:15:29Z")

</div>

[https://github.com/JuliaLang/julia/issues/33192](https://github.com/JuliaLang/julia/issues/33192)

---

<div class="post-metadata">

**Author:** ![brenhinkeller](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brenhinkeller/32/36648_2.png) [@brenhinkeller](https://discourse.julialang.org/u/brenhinkeller)\
**Post date:** [June 8, 2022, 2:47pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/87 "2022-06-08T14:47:58Z")

</div>

> [@miles.lubin](#):
>
> For what it’s worth, the JuMP style guide [recommends](https://jump.dev/JuMP.jl/stable/developers/style/#Exported-and-non-exported-names) underscore prefixes for internal functions. Given that Julia lacks public/private access modifiers (not suggesting that it needs them), it’s useful for callers to have an obvious visual signal as to whether the symbol is internal or external. I agree that the presence of nice documentation per se isn’t a good discriminator between public and private APIs, because private APIs should be documented as well.

Personally I quite like and try to use this convention. Yes, it’s arguably a bit less “pretty” to have to begin private functions with `_` but that’s also I think what makes it so effective.

Base seems to maybe partially (?) use this convention (or at least, there are `_` methods in base and I certainly make sure to never rely on them). Would it be infeasible to adopt this more consistently throughout Base? (maybe for 2.0…)

---

<div class="post-metadata">

**Author:** ![skleinbo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skleinbo/32/36080_2.png) [@skleinbo](https://discourse.julialang.org/u/skleinbo)\
**Post date:** [June 8, 2022, 2:52pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/88 "2022-06-08T14:52:48Z")

</div>

Yes, I have found that issue a while ago too. But there seems to be some hesitance to make it official, and if then probably under a different name.

---

<div class="post-metadata">

**Author:** ![brenhinkeller](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brenhinkeller/32/36648_2.png) [@brenhinkeller](https://discourse.julialang.org/u/brenhinkeller)\
**Post date:** [June 8, 2022, 3:29pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/89 "2022-06-08T15:29:06Z")

</div>

Then there’s absolutely no ambiguity as to what is private: does it begin with `_` ? yes : no. Don’t necessarily even need tooling – though you could certainly add it easily enough, and would not need to worry about annotating things with a special `@public`/`@private` macros.

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [June 8, 2022, 4:03pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/90 "2022-06-08T16:03:44Z")

</div>

As a convention, this solves the problem from one side: as a consumer of an API I can tell at a glance (and I can check programatically reasonably easy) if an API is public or not. Assuming everybody will (afford to) adopt this convention. Because when making a function public or private with a modifier it’s an issue of simply changing it at the place of the function declaration. But _marking_ a function as public/private in an existing codebase, requires replacing all the uses of that function throughout all the codebases.

However, the underscore convention does not cover the other side: a developer that wants to ensure that their internal code can not be utilised outside the boundaries of their own class/module/type/etc hierarchy.

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [June 8, 2022, 4:11pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/91 "2022-06-08T16:11:15Z")

</div>

Yes, 100%

---

<div class="post-metadata">

**Author:** ![BioTurboNick](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bioturbonick/32/6380_2.png) [@BioTurboNick](https://discourse.julialang.org/u/BioTurboNick)\
**Post date:** [June 8, 2022, 4:57pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/92 "2022-06-08T16:57:03Z")

</div>

A lightweight way to improve on what already exists would be:

Exported-public - anything exported is deemed public

Private - anything not exported is deemed private by default

Not-exported public - need a keyword or macro to mark entities as not exported but are part of the API.

That means the degree of change necessary to implement is restricted to methods you want to be public but not exported, which should be relatively few.

Tooling can warn if private entities are used from another module, rather than have any enforcement by the compiler. Have another keyword or macro that allows it to be suppressed, either for a particular line, block of code, or whole module.

No need to enforce a naming convention that would require ecosystem-wide refactoring of all internal code.

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [June 8, 2022, 8:49pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/93 "2022-06-08T20:49:45Z")

</div>

Python at least has more of a culture and tooling (linters, etc.) to support the idea of private methods and attributes. Just one example: Some linters will require you to document a method unless it starts with `_`.

The same convention is sometimes used in Julia. But, it’s much less widespread, and more poorly supported by tooling.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 8, 2022, 11:14pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/94 "2022-06-08T23:14:30Z")

</div>

One thing I can fully agree on is that it sucks when someone contributes code and your library breaks a year later because they snuck in an undocumented internal `Base` method to make something work but didn’t make a note or add a check to the tests. It makes sense to want some guard against that beyond proofreading code at 100% efficiency.

It just doesn’t make sense to appropriate OOP access modifiers for this, Julia doesn’t _have_ classes for access modifiers to encapsulate. Roughly speaking, OOP encapsulation designates what components of a class are accessible by other classes (public methods and few fields) and what are confined implementation details (private fields, methods, even nested classes). It’s not the same, but a non-OOP encapsulation is accomplished by modules separating global scopes, `export`ing select names, or `import`ing select names. That’s why `export`ed names came up in the thread as a hint of public API (though still not as authoritative as documentation).

The talk about access modifiers is suggesting that we should apply to multimethods in modules something designed for members in classes. There’s a lot wrong with this:

1. Internals aren’t confined to their home module, they’re free to be exported within the package to the convenience of the developer and out of the users’ sight.
2. The unit in which an internal operates is not a module, it’s the package. So you could invent access modifiers on a package level…if you’re prepared to sacrifice the ability to inspect and test internals easily. There’s also a complicated unsettled debate on how to develop and test (or not) private members.
3. Unlike a singly dispatched method confined to a class, a multimethod’s definition can be scattered, even across packages. What happens when some methods are marked `@private` and the others are marked `@public`? This straightforward inspiration is just a footgun.
4. What about global variables and macros? Macros aren’t even variables or instances.

There’s been some talk about informal conventions like leading underscores, but I’m not sure it’ll solve the issue at hand. It saves someone from checking documentation or `export`s to know if something is public vs internal, but a proofreader can easily overlook it anyway. Without printing warnings or throwing errors, this’ll only make a very rare mistake somewhat easier to spot. And remember that all our internals would have leading underscores, so when you search the text `._`, most of it would be _your_ internals. And if we want to make an internal public in the next version? Time to find-replace-all every file.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [June 9, 2022, 10:59am UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/95 "2022-06-09T10:59:19Z")

</div>

> [@Sukera](#):
>
> PkgEval is already run for every package in existence before a release and if your package is found to break due to a change in _API_, you will get notified/the change will be reverted (depending on severity).

Thats’s the first time I hear about this notifications thing. Whats’s the notification mechanism, and how to opt into it?

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [June 9, 2022, 11:36am UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/96 "2022-06-09T11:36:25Z")

</div>

> [@aplavin](#):
>
> Thats’s the first time I hear about this notifications thing. Whats’s the notification mechanism, and how to opt into it?

No need for opt in. Last I checked, it was either an issue in your repo, or a revert of the offending change in Base, provided it was an accidental API breakage, not a change to an internal function that doesn’t have stability guarantees. Other cases are when you test for exact numerical reproducibility of e.g. the default RNG number stream or numerical results based on that.

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [June 9, 2022, 12:25pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/97 "2022-06-09T12:25:40Z")

</div>

You can also add a PkgEval badge to your readme if you want: [ANN: Nanosoldier package evaluation -- with badges!](https://discourse.julialang.org/t/ann-nanosoldier-package-evaluation-with-badges/33339)

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [June 9, 2022, 1:46pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/98 "2022-06-09T13:46:56Z")

</div>

> [@Benny](#):
>
> it sucks when someone contributes code and your library breaks a year later because they snuck in an undocumented internal `Base` method

Possibly, but note that in this particular case, @essenciary himself introduced this code. To some extent, this whole discussion is not unlike complaining about missing toes after purchasing, loading, and firing a footgun, that had FOOTGUN printed on it in large block letters.

> [@Benny](#):
>
> guard against that beyond proofreading code at 100% efficiency

Again, I am not necessarily disagreeing — if we had a good technical solution here, it would make sense to apply it. Just want to point out that this is a relatively benign bug, because

1. it can be easily tested for _ex ante_ (`@assert isdefined(SomeModule, :internals_I_used)`), and caught by CI,

2. if it is nevertheless missed, things break immediately and visibly, instead of some silent error that corrupted something and you discover a year later,

3. it can be tracked down super-quickly (top of the stack trace).

Unfortunately, 99%+ of bugs are nastier than this, because of one reason or another. This is why people do use internals from other modules in Julia as a workaround, in an admittedly rather informal way, and also why there is no great pressure to fix this — it is relatively innocuous as bugs go.

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [June 9, 2022, 2:44pm UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/99 "2022-06-09T14:44:14Z")

</div>

> [@Tamas\_Papp](#):
>
> To some extent, this whole discussion is not unlike complaining about missing toes after purchasing, loading, and firing a footgun, that had FOOTGUN printed on it in large block letters.

@Tamas_Papp as already mentioned, it’s a generic discussion about methodology and the general way of doing things. The issues I raised stand, regardless of the exact specific of this incident. I would appreciate it if you’d keep the discussion at technical topics and abstain from comments about people.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 10, 2022, 3:05am UTC](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035/100 "2022-06-10T03:05:21Z")

</div>

Proposed breaking changes to the language’s design aside, what does `Base.modules_warned_for` even do? The most I could figure out is `Base.modules_warned_for == Set{Base.PkgId}()`. Any chance the removed code is simple enough to be repurposed for your package’s own internal code? Seems a bit like plagiarism but maybe this is fair game for internal code? Just seems like a faster option than contributing to the language standard.

[Previous page](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035.md?page=4)

[Next page](https://discourse.julialang.org/t/base-modules-warned-for-silently-removed-in-1-8/79035.md?page=6)
