/
CLR Generic Types.html
80 lines (79 loc) · 7.4 KB
/
CLR Generic Types.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<div class="wikidoc">
<h1>CLR Generic Types</h1>
<p>The CLR has <em>three </em>types of “generic type”: <em>Open</em> generic types, <em>partially-open</em> generic types and <em>closed</em> generic types. An open generic type is also called a generic type
definition. An <em>open generic type</em> is one where all of its generic type parameters remain “open” because none of them have been bound to a specific type argument. A <em>partially-open generic type</em> is one where some,
but not all, of the type’s generic type parameters have been bound to specific type arguments. A closed generic type is one where all of the type’s generic type parameters have been bound to specific type arguments. For the most part, a <em>partially-open</em> generic
type is essentially the same as an <em>open</em> generic type. The distinction that really matters is between <em>closed generic types</em> and ones that have generic type parameters that aren’t bound to a specific type.</p>
<p>It’s possible to create instances of closed generic types, but it is not possible to create instances of open or partially-open generic types. And that can be a problem, because .Net class libraries typically only provide <em>generic type definitions</em> that
define <em>open generic types</em>. So, although you can define an Essence# class that represents a .Net type that is an open generic type definition, you won’t be able to use that Essence# class to create instances of the type by sending it the
normal instance creation messages (e.g, #new or #new:). Creating instances of such a type requires providing one or more types that will be used as the type arguments to construct a closed generic type from the open generic type defined by the .Net class
library.</p>
<h2>Constructing Closed Generic Types</h2>
<p>Fortunately, you can use Essence# to construct a closed generic type from an open generic type definition, as illustrated in the following example:</p>
<pre>| openGenericDictTypeDefinition esClass closedGenericType |
openGenericDictTypeDefinition :=
'System.Collections.Generic.Dictionary`2' asHostSystemType.
esClass := openGenericDictTypeDefinition asClass.
closedGenericType := esClass
instanceTypeWith: Type string
with: Type string.
dict := closedGenericType new.
dict at: #foo
ifPresent:
[:value |
System.Console
write: 'The value at #foo is ';
writeLine: value
]
ifAbsent:
[
System.Console writeLine: '#foo is not present'
].
dict at: #foo put: #bar.
dict at: #foo
ifPresent:
[:value |
System.Console
write: 'The value at #foo is ';
writeLine: value
]
ifAbsent:
[
System.Console writeLine: '#foo is not present'
].</pre>
<p> </p>
<p>As mentioned in the article on <a href="https://essencesharp.codeplex.com/wikipage?title=Using%20CLR%20Types&referringTitle=Documentation">
using CLR types</a>, the Essence# class that represents a CLR type can be obtained by sending the message #asClass to the CLR type object.</p>
<p>If an Essence# class represents a generic type (whether the type is open, partially-open or closed makes no difference,) then you can create a closed generic type by sending one of the following messages to the Essence# class: #instanceTypeWith: <em>aCLRType</em>,
#instanceTypeWith:<em>aCLRType </em>with: <em>aCLRType</em>, #instanceTypeWith: <em>aCLRType </em>with: <em>aCLRType </em>with: <em>aCLRType , , #instanceTypeWith: <em>aCLRType </em>with: <em>aCLRType </em>with: <em>aCLRType</em></em>,
#instanceTypeWith:<em>aCLRType </em>with: <em>aCLRType </em>with: <em>aCLRType </em>with: <em>aCLRType </em>with: <em>aCLRType</em> or #instanceTypeWithAll: <em>anArrayOfCLRTypes</em>.</p>
<h3>Defining Essence# Classes That Represent Closed Generic Types</h3>
<p>One good way to handle the case where the .Net type you want to use is an open generic type definition would be to define a subclass of an Essence# class that represents that type, and then use one of the messages above to construct a closed generic
type that will be the instance type of the subclass.</p>
<p>Another good way to do it is simply to use the CLR’s syntax for closed generic types when specifying the instance type of the subclass. The following examples show both approaches:</p>
<pre>"Class creation/configuration using the Essence# #instanceTypeWith: message"
| superclass class |
superclass := 'System.Collections.Generic.List`1, mscorlib'
asHostSystemType asClass.
class := Class new.
class
superclass: superclass;
instanceType: (superclass instanceTypeWith: System.Type object).
</pre>
<p> </p>
<pre>"Class creation/configuration using the CLR's syntax for closed generic types"<br> | class |<br> class := Class new.<br> class <br> assemblyName: 'mscorlib';<br> hostSystemNamespace: #System.Collections.Generic;<br> hostSystemName: 'List`1[[System.Object]]'</pre>
<p> </p>
<h3>Open Generic Type Definitions</h3>
<p>It's also not only possible to define an Essence# class that represents an open generic type definition, the system actually does that for you automatically. And there's a reason it does so:</p>
<p>An Essence# class that represents any closed generic type inherits from the Essence# class that represents the corresponding open generic type definition. For example, the class Smalltalk.Set–which represents the .Net type System.Collections.Generic.HashSet<Object>)–inherits
from the Essence# class that represents the .Net type System.Collections.Generic.HashSet<>. </p>
<p>And that matters because best practice would be to define most of the user-primitives used to adapt a generic type for use by Essence# in the Essence# class the represents the open generic type definition, instead of in ones that represent any of the corresponding
closed generic types.</p>
<p>To define an Essence# class that represents an open generic type definition in an
<a href="https://essencesharp.codeplex.com/wikipage?title=Class%20Libraries&referringTitle=Documentation">
Essence# class library</a>, the default way to do that is to use the CLR's name for the open generic type definition as the name of the class--even though that class name is not a legal global variable reference. In the case of the open generic type definition System.Collections.Generic.HashSet<>,
the CLR name is System.Collections.Generic.HashSet`1 (which you will find already defined for your in the namespace CLR.System.Collections.Generic in the
<a href="https://essencesharp.codeplex.com/wikipage?title=Standard%20Library&referringTitle=Documentation">
Essence# Standard Library</a>.)</p>
<p><em>The essence of OOP: It's all messages, all the time.</em></p>
</div><div class="ClearBoth"></div>