Scala stylish abstract modules in C # or in other languages?

I looked at Martin Odersky’s book “Programming” in Scala with her section on abstract modules and his article “Scalable Components of Abstractions”:

http://lampwww.epfl.ch/~odersky/papers/ScalableComponent.pdf

My contribution is that by making your modules abstract classes instead of objects (or classic static global modules like Java):

abstract class myModule{ // this is effectively an abstract module, whose concrete // components can be configured by subclassing and instantiating it class thing{} class item{} object stuff{} class element{} object utils{} } 

You can create an instance of several subclasses and module instances with various specific characteristics. This allows you to configure the module differently depending on the circumstances (for example, replacing the database component during testing or the IO component in the dev environment), as well as create several modules each with its own set of changed module state.

From what I can understand, at a basic level, the only tough requirement is that you can have nested classes, so that the enclosing class can act as a module.

Another practical requirement is that you can decompose the class definition into several files, since a module with a bunch of classes in it will probably have more lines of code than most will accept in a single source file.

Scala does this with Traits, which bring some other positive effects that are good, but not central to the entire class of abstract extension module, regarding the idea of ​​multiple source files. C # has partial classes , which provides the same functionality, and also allows nested classes. Presumably, some other languages ​​have similar support for nested classes, as well as splitting a class into multiple files.

Is this type of template anywhere in C # or in any other languages? I think that large projects in many languages ​​are faced with a problem that abstract modules must solve. Is there a reason why this "abstract-class as an abstract module" does not work, and therefore is not used? It seems to me that this is a much cleaner solution than the various DI frameworks offering the same functionality.

+6
source share
2 answers

The abstract module that you describe has the following basic properties:

  • This is a closed module, meaning that it provides an entire interface that allows you to interact with the module
  • You can specify operations on the module
  • You can specify types that are part of the module - usually these types are controlled by the above modules
  • The implementation is not provided - this is the abstract part: there can be many specific implementations and which is actually used in the program will be set and selected by the program, since it is best suited

A function that allows you to specify a module that uses more than one source file is not a basic requirement, but it may come in handy.

In its basic form, the module describes an abstract data type (for example, a queue): what operations are available for interacting with a data type and any auxiliary types necessary for interaction.

In a more complex form, it can describe a whole subsystem (for example, a network).

In imperative languages, you usually use an interface for the same purpose:

  • Attached
  • You can specify operations
  • You can specify types that are part of the interface.
  • No implementation

As you already mentioned, if your module has a large interface (for example, describes a subsystem), it is usually impractical to write classes that implement a rich interface in a single file. If the language does not provide support for splitting the same class into separate sources (or more precisely: for “gluing” separate parts of the same class from different source files together), the solution is usually to lose the attached requirement and ensure a series of interfaces that define the interactions between them - this way you get an API for a subsystem (this is an API in the pure sense: this is an interface for interacting with a subsystem, without implementation yet).

In a sense, this latter approach may be more general (general in the sense of what you can achieve with it) than the closed type: you can provide the implementation of various subtypes (defined via interfaces) from different authors: while the subtypes rely only on the specified interface to interact with each other, this mix-n-match approach will work.

One of the strengths of most functional programming languages ​​is parameterized data types, where you create a dayatype type with another as your parameter (for example, an integer queue). The same flexibility is achieved with Generics in Java / C # (and C ++ templates). Of course, the exact consequences and expressive power may vary between languages ​​based on their type system.

This entire discussion is a separate form of Injection Dependency (DI), which attempts to weaken the strong relationship between a particular type implementation and its supporting parts by explicitly providing the necessary parts (as opposed to choosing an implementation), since the type user can better understand which implementation of these parts best to achieve your goal - for example, by providing mock implementations for testing functionality.

The DI problem is trying to solve exclusively for imperative languages, you can have the same dependency problems in functional languages: an abstract module implementation can use a specific subtype implementation (thus linking itself to these implementations) instead of using subtype implementations as parameters (to what DI strives for)

+2
source

The usual comparison is with ML modules, where Scala features (or abstract classes) play the role of ML signatures and their concrete implementations (usually Scala objects) play the role of ML structures. A discussion of ML modules here should make the connection understandable.

The analogy between Scala and ML is intentional, and if you look at the source of the Scala compiler, you will see that Scala objects often refer to names containing the "Module" as part.

+8
source

Source: https://habr.com/ru/post/917588/


All Articles