lib: add `meta` as a user-level empty shell for meta-classes
authorJean Privat <jean@pryen.org>
Thu, 19 Mar 2015 05:40:42 +0000 (12:40 +0700)
committerJean Privat <jean@pryen.org>
Thu, 19 Mar 2015 05:40:42 +0000 (12:40 +0700)
Signed-off-by: Jean Privat <jean@pryen.org>

lib/meta.nit [new file with mode: 0644]
tests/sav/nitg-e/test_meta.res [new file with mode: 0644]
tests/sav/nitg-g/fixme/test_meta.res [new file with mode: 0644]
tests/sav/nitg-s/fixme/test_meta.res [new file with mode: 0644]
tests/sav/nitg-sg/fixme/test_meta.res [new file with mode: 0644]
tests/sav/test_meta.res [new file with mode: 0644]
tests/test_meta.nit [new file with mode: 0644]

diff --git a/lib/meta.nit b/lib/meta.nit
new file mode 100644 (file)
index 0000000..68ba9f4
--- /dev/null
@@ -0,0 +1,99 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Simple user-defined meta-level to manipulate types of instances as object.
+#
+# Unfortunately, since the meta-objects are user-defined they are provided without
+# any pre-defined information or behavior.
+# For the same reasons, the Nit OO mechanisms do not rely on this user-defined meta-level.
+#
+# However `meta` permits the definition of user-defined meta-classes at any level
+# of meta, even with user-defined meta-loops.
+#
+# ## Meta-classes
+#
+# Meta-classes can be defined easily in 3 steps:
+#
+# * define a root for the class hierarchy (eg `XObject`)
+# * define a meta-class (eq `XClass[E: XObject] super Class[E]`)
+# * redefine `CLASS` and `class_factory` in the root
+#
+# ~~~nitish because broke with nitc, see Limitation bellow
+# class XObject
+#    redef CLASS: XClass[SELF]
+#    redef class_factory(name) do return new XClass[SELF](name)
+# end
+# class XClass[E: XObject] super Class[E] end
+#
+# var x1 = new XObject
+# var x2 = new XObject
+# assert x1.get_class == x2.get_class
+# assert x1.get_class isa XClass[XObject]
+# assert x1.get_class.get_class isa Class[XClass[XObject]]
+# ~~~
+#
+# ## Limitation
+#
+# Currently works only with the interpreter `nit` and the compiler with `--erasure` (without `--rta`).
+#
+# `--rta` will try to detect all the runtime types, and will infinitely discover `Class[Class[Class[....]]]`.
+# Unfortunately, `--separate` and `--global` require `--rta`.
+#
+# Moreover, the interpreter and `--erasure` have a different behavior with generics since
+# with `--erasure` a single meta-instance is shared for all type variations of a same generic class.
+#
+# Class names are used as a primary key to identify classes.
+# But name conflicts are not managed and will make the program crashes at runtime (on some cast error)
+module meta
+
+redef class Object
+       # The meta-object representing the dynamic type of `self`.
+       #
+       # Specific meta-object can be used in subclasses
+       # by redefining `CLASS` and `class_factory`.
+       fun get_class: CLASS do
+               var class_pool = once new HashMap[String, Class[Object]]
+               var name = class_name
+               var res = class_pool.get_or_null(name)
+               if res != null then return res.as(CLASS)
+               res = class_factory(name)
+               assert res.name == name
+               class_pool[name] = res
+               return res
+       end
+
+       # The type of the class of self.
+       # To be redefined in case of specific meta-class.
+       type CLASS: Class[SELF]
+
+       # Implementation used by `get_class` to create the specific class.
+       #
+       # To be redefined to use specific meta-classes.
+       #
+       # Note: Do not forget to update the virtual type `CLASS`.
+       #
+       # REQUIRE: `result.name` == `name`
+       protected fun class_factory(name: String): CLASS
+       do
+               return new Class[SELF](name)
+       end
+end
+
+# This meta-class is the root the meta-class hierarchy
+class Class[E: Object]
+       # The name of the class
+       var name: String
+
+       redef fun to_s do return name
+end
diff --git a/tests/sav/nitg-e/test_meta.res b/tests/sav/nitg-e/test_meta.res
new file mode 100644 (file)
index 0000000..ad6cdbf
--- /dev/null
@@ -0,0 +1,14 @@
+FlatString
+FlatString
+Class
+Class
+
+XObject
+XObject
+XClass
+Class
+
+YObject
+YObject
+YClass
+YClass
diff --git a/tests/sav/nitg-g/fixme/test_meta.res b/tests/sav/nitg-g/fixme/test_meta.res
new file mode 100644 (file)
index 0000000..4ad3dc3
--- /dev/null
@@ -0,0 +1 @@
+UNDEFINED
diff --git a/tests/sav/nitg-s/fixme/test_meta.res b/tests/sav/nitg-s/fixme/test_meta.res
new file mode 100644 (file)
index 0000000..4ad3dc3
--- /dev/null
@@ -0,0 +1 @@
+UNDEFINED
diff --git a/tests/sav/nitg-sg/fixme/test_meta.res b/tests/sav/nitg-sg/fixme/test_meta.res
new file mode 100644 (file)
index 0000000..4ad3dc3
--- /dev/null
@@ -0,0 +1 @@
+UNDEFINED
diff --git a/tests/sav/test_meta.res b/tests/sav/test_meta.res
new file mode 100644 (file)
index 0000000..6f23d37
--- /dev/null
@@ -0,0 +1,14 @@
+FlatString
+FlatString
+Class[FlatString]
+Class[Class[FlatString]]
+
+XObject
+XObject
+XClass[XObject]
+Class[XClass[XObject]]
+
+YObject
+YObject
+YClass[YObject]
+YClass[YClass[YObject]]
diff --git a/tests/test_meta.nit b/tests/test_meta.nit
new file mode 100644 (file)
index 0000000..936982e
--- /dev/null
@@ -0,0 +1,56 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import meta
+
+class XObject
+       redef type CLASS: XClass[SELF]
+       redef fun class_factory(name) do return new XClass[SELF](name)
+end
+
+class XClass[E: XObject]
+       super Class[E]
+end
+
+class YObject
+       redef type CLASS: YClass[SELF]
+       redef fun class_factory(name) do return new YClass[SELF](name)
+end
+
+class YClass[E: YObject]
+       super Class[E]
+       super YObject # Yeah, a meta-loop!
+end
+
+var s = "hello"
+print s.class_name
+print s.get_class
+print s.get_class.get_class
+print s.get_class.get_class.get_class
+
+print ""
+
+var x = new XObject
+print x.class_name
+print x.get_class
+print x.get_class.get_class
+print x.get_class.get_class.get_class
+
+print ""
+
+var y = new YObject
+print y.class_name
+print y.get_class
+print y.get_class.get_class
+print y.get_class.get_class.get_class