examples: annotate examples
[nit.git] / lib / meta.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Simple user-defined meta-level to manipulate types of instances as object.
16 #
17 # Unfortunately, since the meta-objects are user-defined they are provided without
18 # any pre-defined information or behavior.
19 # For the same reasons, the Nit OO mechanisms do not rely on this user-defined meta-level.
20 #
21 # However `meta` permits the definition of user-defined meta-classes at any level
22 # of meta, even with user-defined meta-loops.
23 #
24 # ## Meta-classes
25 #
26 # Meta-classes can be defined easily in 3 steps:
27 #
28 # * define a root for the class hierarchy (eg `XObject`)
29 # * define a meta-class (eq `XClass[E: XObject] super Class[E]`)
30 # * redefine `CLASS` and `class_factory` in the root
31 #
32 # ~~~nitish because broke with nitc, see Limitation bellow
33 # class XObject
34 # redef CLASS: XClass[SELF]
35 # redef class_factory(name) do return new XClass[SELF](name)
36 # end
37 # class XClass[E: XObject] super Class[E] end
38 #
39 # var x1 = new XObject
40 # var x2 = new XObject
41 # assert x1.get_class == x2.get_class
42 # assert x1.get_class isa XClass[XObject]
43 # assert x1.get_class.get_class isa Class[XClass[XObject]]
44 # ~~~
45 #
46 # ## Limitation
47 #
48 # Currently works only with the interpreter `nit` and the compiler with `--erasure` (without `--rta`).
49 #
50 # `--rta` will try to detect all the runtime types, and will infinitely discover `Class[Class[Class[....]]]`.
51 # Unfortunately, `--separate` and `--global` require `--rta`.
52 #
53 # Moreover, the interpreter and `--erasure` have a different behavior with generics since
54 # with `--erasure` a single meta-instance is shared for all type variations of a same generic class.
55 #
56 # Class names are used as a primary key to identify classes.
57 # But name conflicts are not managed and will make the program crashes at runtime (on some cast error)
58 module meta
59
60 redef class Object
61 # The meta-object representing the dynamic type of `self`.
62 #
63 # Specific meta-object can be used in subclasses
64 # by redefining `CLASS` and `class_factory`.
65 fun get_class: CLASS do
66 var class_pool = once new HashMap[String, Class[Object]]
67 var name = class_name
68 var res = class_pool.get_or_null(name)
69 if res != null then return res.as(CLASS)
70 res = class_factory(name)
71 assert res.name == name
72 class_pool[name] = res
73 return res
74 end
75
76 # The type of the class of self.
77 # To be redefined in case of specific meta-class.
78 type CLASS: Class[SELF]
79
80 # Implementation used by `get_class` to create the specific class.
81 #
82 # To be redefined to use specific meta-classes.
83 #
84 # Note: Do not forget to update the virtual type `CLASS`.
85 #
86 # REQUIRE: `result.name` == `name`
87 protected fun class_factory(name: String): CLASS
88 do
89 return new Class[SELF](name)
90 end
91 end
92
93 # This meta-class is the root the meta-class hierarchy
94 class Class[E: Object]
95 # The name of the class
96 var name: String
97
98 redef fun to_s do return name
99 end
100
101 # Helper to get the name of a type
102 #
103 # This is one of the hackiest way to retrieve the name of a random type.
104 #
105 # ~~~
106 # var dummy = new GetName[Sequence[nullable Comparable]]
107 # assert dummy.to_s == "Sequence[nullable Comparable]"
108 # ~~~
109 #
110 # This also works to resolve formal types
111 #
112 # ~~~
113 # class G[T]
114 # type V: Collection[T]
115 #
116 # var name_of_v: String = (new GetName[V]).to_s is lazy
117 # end
118 #
119 # var g = new G[Bool]
120 # assert g.name_of_v == "Collection[Bool]"
121 # ~~~
122 #
123 # Warning: this does not work if --erasure is used.
124 class GetName[E]
125 redef fun to_s do
126 var name = class_name
127 if name.length < 9 then return ""
128 return name.substring(8, name.length-9)
129 end
130 end