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

Drop-in replacement packages #80

Open
LPeter1997 opened this issue Aug 13, 2022 · 2 comments
Open

Drop-in replacement packages #80

LPeter1997 opened this issue Aug 13, 2022 · 2 comments
Labels
Language idea One single idea which may be a start of a design document

Comments

@LPeter1997
Copy link
Member

Introduction

The discussion in #58 brought up an interesting point (starting here) about the ability to rewrite a package with the exact API in the exact namespaces to be able to replace it in a codebase without any modifications. This can be a legit use-case and something the module system issue doesn't 100% address.

The problem

If our application or library consumes some dependency, it is usually coupled with that dependency in-source. For example, using some advanced math library called AdvancedMath in C#:

using AdvancedMath.Matrices;

var a = Mat4.Identity() * 0.5;
var b = Mat4.Diagonal(1, 2, 3, 4);
var c = a * b;

As you can see, the name of the project - AdvancedMath - was used for the root namespace of the library, as the usual convention in .NET.

Now let's assume, there is a bug in the library, or it has inefficiencies that has to be solved in out application. In a real-world scenario, you might not have access to the original source or don't have the opportunity to report a bug/fix the issue yourself in the original project.

Solution in C#

Currently in C# you'd develop your own library with an identical API, and to avoid any code changes, you'd define it under the same namespaces. Despite this being another implementation, from the outside this looks exactly like the other one on the consumer side.

While this solution works, it has a couple of weak points:

  • The package "lies", it diverges from the convention. It becomes very unclear where a given functionality actually came from. When seeing Newtonsoft.Json, I can't assume it's from the original JSON library anymore.
  • The reimplemented package ties itself to the original package. It uses the same namespace as the original one for the sole purpose of avoiding code change. Instead of renaming on the consumer side, the renaming happens on producer side, severely limiting reuse.
  • Using both packages becomes a bit more cumbersome, requiring extern aliasing.

Solution for Fresh applications consuming Fresh libraries

The current modules issue (#58) makes it relatively easy to re-expose dependencies in a package-agnostic way. The consumer library could collect out the used API from a module and re-export it as its own module:

module math
{
    export Mat4 from AdvancedMath;
}

From then on, all consuming code can reference math.Mat4. If the implementation needs to be replaced, every element can be exported and aliased in this locally defined module. There is no reason for "namespace" hacking, and the replacement can be re-used for other APIs. Furthermore, if there are slight API differences, this local module is the perfect place to roll the adapters, decoupling the dependency even more.

Another very simple way would be allowing to alias the package name of imported dependencies right in the projectfile:

<PackageReference Name="FixedMath" Alias="AdvancedMath" />

Solution for other .NET languages consuming Fresh libraries

I believe this is the place where the module system issue (#58) would have to provide a solution, as we'd need some control to be able to generate arbitrary namespace structures that might not follow the module structures.

We could also not provide first-class support for this, or have a metadata-based generator that could build up C# wrapper packages for the library.

Other possible solutions

There have been vague ideas flying around about how else we could solve this problem. Any other worked out idea could fill this section.

@LPeter1997 LPeter1997 added the Language idea One single idea which may be a start of a design document label Aug 13, 2022
@Kuinox
Copy link
Member

Kuinox commented Aug 17, 2022

A package name provide an identity: only authors of a packages, can push changes to this package.
Module imports allow you to know which package use some code, which also mean you know who maintain these package.
I have no issue with module re-exports, package having dependencies always happened. Nothing stop you from wrapping dependencies methods.
But I'm against aliases: it break the relation I described.

If you swap a package, it should lead to imports change.

@LPeter1997
Copy link
Member Author

A package name provide an identity

Yes, that's the idea of our modules proposal.

If you swap a package, it should lead to imports change.

I completely agree! The alias is mostly there for legacy systems, where you don't really want to (or can't) touch that code. It's likely not something that we will encourage, it should be a last resort.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Language idea One single idea which may be a start of a design document
Projects
None yet
Development

No branches or pull requests

2 participants