Draco-lang / Language-suggestions

Collecting ideas for a new .NET language that could replace C#
75 stars 5 forks source link

Drop-in replacement packages #80

Open LPeter1997 opened 2 years ago

LPeter1997 commented 2 years ago

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:

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.

Kuinox commented 2 years ago

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 commented 2 years ago

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.