How do I represent an aggregation relation between two classes in UML, such that each class has a link to the other class's interface, not the implementing class?
E.g. I have a class Foo that implements iFoo, and Bar that implements iBar. Foo should have a member variable of type iBar, and Bar should have a member variable of type iFoo.
If I create an aggregation between the two implementing classes, then the member will be of the type of the implementing class, not the superclass. And aggregations between interfaces are invalid in UML (and don't make much sense).
Can you not have Foo (implementation) aggregate iBar (interface)? That seems to me the proper way to describe this relationship.
So something like this:
----------------- -----------------
| <<interface>> | | <<interface>> |
| iFoo |<> <>| iBar |
----------------- \/ -----------------
^ /\ ^
| / \ |
-----------------/ \-----------------
| Foo | | Bar |
----------------- -----------------
Interfaces are not instantiable, so Bar cannot have an attribute of type iFoo, and Foo cannot have an attribute of type iBar.
You say you don't want an Association between Bar and Foo. So you could create a new Class (FooEx) and have that Class implement iFoo. Then Bar can have an Association to FooEx instead of Foo.
Related
I want to make an interface with default implementation for equality and comparison functions.
If I remove everything from the type IKeyable<'A> except the Key member, it is a valid interface, as long as I don't add a default implementation. Removing the other interface implementations from IKeyable<'A>, and leaving just default members ends in the same result.
type IKeyable<'A when 'A: equality and 'A :> IComparable> =
abstract member Key : 'A
default this.Equals obj = // hidden for clarity
default this.GetHashCode () = // hidden for clarity
interface IEquatable<'A> with
member this.Equals otherKey = // hidden for clarity
interface IComparable<'A> with
member this.CompareTo otherKey = // hidden for clarity
interface IComparable with
member this.CompareTo obj = // hidden for clarity
type Operation =
{ Id: Guid }
interface IKeyable<Guid> with // Error: The type 'IKeyable<Guid>' is not an interface type
member this.Key = this.Id
I would like to make use of IKeyable<'A> as an interface in order to "gain" the default implementations for equality and comparison.
The error message comes up on the interface ... with under the type Operation: The type 'IKeyable<Guid>' is not an interface type
An interface cannot have method implementations, and your type has five of them - Equals, GetHashCode, IEquatable<_>.Equals, IComparable<_>.CompareTo, and IComparable.CompareTo.
An interface is purely a set of method and properties. It's not like a base class, it cannot give the implementor some "default" implementations or base behavior or utility methods it anything like that.
To make your type an interface, get rid of all the implementations:
type IKeyable<'A when 'A: equality and 'A :> IComparable> =
inherit IEquatable<'A>
inherit IComparable<'A>
abstract member Key : 'A
If you really want to keep the default implementations, you have to make it a base class rather than interface, in which case Operation must become a class rather than a record:
type Operation(id: Guid)
inherit IKeyable<Guid>
override this.Key = id
member val Id = id
Let's say I have this :
class type point_t =
object
val x : int
method getx : int
method move : int -> unit
end;;
I can write a class like this and it will work :
class point : point_t =
object
val mutable x = 0
method getx = x
method move d = x <- x + d
end;;
Now suppose that I want to create a class type that would NOT allow a class to be defined with a mutable val x (I want x to be immutable). Is there a way to do that ?
It is not possible, so if you don't want to allow implementations to use a mutable variable it is better just to hide it all and expose functional getter/setter:
class type point_t = object(self)
method get_x : int
method with_x : int -> self
method move : int -> self
end;;
You may omit with_x method if you want to allow updates only via the move method.
The reasoning for this is that a class with a mutable version of a variable is a proper subclass of a class with immutable version of the same variable, as it has the same set of operations, plus one more - an ability to set the variable. So, any abstraction over a type point_t can be applied to a class instance with and without a mutability (although it will not be able to mutate the variable). Note, that the opposite is not possible, if you will define the class type point_t with a mutable x, and will try to implement it with an immutable one, then the type system will complain. As your implementation doesn't provide all the operations.
Also, there is one thing that you possibly miss. Although, the class point has a mutable variable x this mutability is actually sealed (i.e., hidden) by the type constraint point_t. So, no matter what is the implementation, the interface is strictly defined to have immutable x:
class the_point = object
inherit point
method! move d = x <- x - d
end
method! move d = x <- x - d
^^^^^^^^^^
Error: The instance variable x is not mutable
Your confusion may arise from the fact that you have some experience with Java/C++ style of OOP, where class types are nominal, and a class can became a subclass of another class only by explicit inheritance. In OCaml a class is a subclass of another class if it is a syntactical superset of it, i.e., if it has at least all fields of the super class. There is no need to inherit from a super class, to become its subclass. And class point : point_t is not an inheritance, but a type constraint, that says: here is the class expression, that implements point_t class (and maybe more), please, make sure that it is true and expose only point_t interface to the outsiders.
And a final note, I've specifically denoted term sub classing as the syntactic super set of a super class to emphasize the fact that inheritance and sub classing do not imply subtyping. The latter is the semantics (i.e., the behavior of an instance), the former is syntax, i.e., a set of code fragments. Subclassing gives you a code reuse, the ability to copy the code from superclasses (as inherit is actually just copy/pasting the code of super class to your sub class). The subtyping gives you the polymorphism - an ability to use the same abstraction on different implementations.
I thought "hygiene" would prevent collisions between Xs defined within my macro m! but that turned out not to be the case. What am I misunderstanding?
macro_rules! m {
($e:expr) => {
const X: i32 = $e;
};
}
m!(0);
m!(1);
fn main() {
m!(2);
m!(3);
}
Playground
Error message:
error[E0428]: the name `X` is defined multiple times
--> src/main.rs:3:9
|
3 | const X: i32 = $e;
| ^^^^^^^^^^^^^^^^^^
| |
| `X` redefined here
| previous definition of the value `X` here
...
7 | m!(0);
| ------ in this macro invocation
|
= note: `X` must be defined only once in the value namespace of this module
From The Rust Programming Language (first edition)'s section on macro hygiene:
This [i.e. renaming] holds for let bindings and loop labels, but not for items
The Rust reference defines items:
An item is a component of a crate. Items are organized within a crate
by a nested set of modules. Every crate has a single "outermost"
anonymous module; all further items within the crate have paths within
the module tree of the crate.
Items are entirely determined at compile-time, generally remain fixed
during execution, and may reside in read-only memory.
There are several kinds of items:
modules
extern crate declarations
use declarations
function definitions
type definitions
struct definitions
enumeration definitions
union definitions
constant items
static items
trait definitions
implementations
extern blocks
This makes sense: if you you introduce an item in a macro you presumably want to actually use it from other items/modules/crates (and thus outside the macro), but you can't if you don't know its name, so the compiler can't rename it.
I saw that in F# its very easy to define a type which is a combined from a set of other types such as
type MyFiveNumbers = One | Two | Three | Four | Five
This looks just great!
What is the simplest way to do that in Scala?
One and the rest are not types, but union cases. The Scala equivalent in fact does make them types:
sealed trait MyFiveNumbers
case object One extends MyFiveNumbers
case object Two extends MyFiveNumbers
...
In such a simple case you might be best off just using a Java enum. However, if any constructors have parameters (e.g. add | Other of int to the end), they correspond to Scala case classes:
case class Other(x: Int) extends MyFiveNumbers
You can use pattern matching just as in F#:
// x has type MyFiveNumbers
x match {
case One => ...
...
case Other(n) => ...
}
and get compiler warnings about incomplete matches (only if the sealed keyword is used; otherwise you can create additional cases in other files).
The author of the question
Exchanging type parameters with abstract types wrote a => at the beginning of his class definitions. Example:
abstract class Thing { t =>
type A
type G <: Group { type A = t.A }
val group: G
}
What does the t => mean ?
Because this is hard to find in Google & Co, can someone please give me more background information or provide a link, where I can find more information about this language construct ?
The default naming for class itself is this. You may replace it with t by t =>
It is useful if your class contains subclasses and you need access to enclosing self reference.
Without t => in your example you would write something like this:
abstract class Thing {
type G <: Group { type A = this.A }
}
Group { type A = this.A } is a subtype so this would reference to group specialization itself not to a thing object. Probably you get not what you mean to get. If you need access to Thing self reference you should resolve name conflict by assigning self reference another name
abstract class Thing { another_this = >
type G <: Group { type A = another_this.A}
}
It is indeed self type annotation. See the official Scala specification:
https://scala-lang.org/files/archive/spec/2.13/13-syntax-summary.html
According to this specification, its context free EBNF syntax is:
SelfType ::= id [‘:’ Type] ‘=>’
| ‘this’ ‘:’ Type ‘=>’
So, basically, this means SelfType has two basic forms. In one form, you can use an id with or without Type. In the other, you can use this but it must be accompanied with a Type.
You can find it in section 29.4 of Programming in Scala Second Edition. However, remember that books can be quickly out of date, so you need to refer to the specification.