How are enums augmentable? - enums

In Raku, HOWs must expose a list of archetypes through an archetypes method, which is used to determine what broader features of types a type implements, e.g. parametricity or composability. I noticed Metamodel::EnumHOW (the HOW used with enums) has the augmentable archetype, which is given to types that can be extended after composition with the augment keyword when the MONKEY-TYPING pragma is enabled.
My first guess at why enums would be augmentable would be to allow enum values to be added, so I tried writing this:
use v6;
use MONKEY-TYPING;
enum Foo <foo bar baz>;
augment enum Foo <qux>;
say qux;
But this throws:
bastille% raku test.raku
===SORRY!=== Error while compiling /home/morfent/test.raku
Redeclaration of symbol 'Foo'.
at /home/morfent/test.raku:5
------> augment enum Foo⏏ <qux>;
So they're probably not intended to be augmented in this way.
My next guess was that they're intended to be augmentable with regards to the enum values, not the enum type itself. augment, interestingly, doesn't take into account what HOW a type actually has when you tell it what kind of type you're augmenting, so I tried augmenting an enum like you would a class:
use v6;
use MONKEY-TYPING;
enum Foo <foo bar baz>;
augment class Foo {
proto method is-foo(::?CLASS:D: --> Bool:D) {*}
multi method is-foo(foo: --> True) { }
multi method is-foo(::?CLASS:D: --> False) { }
}
say foo.is-foo;
Which works:
bastille% raku test.raku
True
But this doesn't feel like how you're intended to augment enums to me. This usage of augment is rather weird, and there isn't any implication that this should be possible to do from its documentation. How are you intended to augment enums?
FAQ
Foo.is-foo doesn't appear to have any code? What is it doing?
is-foo is rather heavy-handed with how it uses features of signatures and parameters. It depends on the following:
Constant values may be used like types in signatures. This includes enum values, which are dealt with at compile-time.
A routine can be made to always return a constant value by making one its signature's return value's type.
Variables for any given parameter in a signature are optional.
When a colon is placed after the first parameter like this, that first parameter is the signature's invocant. In the case of methods, this allows you to type self however you want.
::?CLASS is an alias for the class whose scope a method is declared in. This exists in class and role bodies, so despite Foo not really being a class, that is what the symbol is referring to.
:D is a type smiley denoting that a type should only typecheck against its own instances, not type objects that typecheck like it.
Since foo is a more specific type than ::?CLASS:D (an alias for Foo:D), when invoking this method on foo, the foo multi will be selected and True will get returned, but in any other case, the ::?CLASS:D multi will be selected and False will be returned.

In Java you can add almost arbitrary attributes and functions to enums. So I do think augment in the way you describe could make sense. For example:
use MONKEY-TYPING;
enum Days(Monday => 1, Tuesday => 2, Wednesday => 3, Thursday => 4, Friday => 5, Saturday => 6, Sunday => 7);
augment class Days {
proto method is-weekend(::?CLASS:D: --> Bool:D) {*}
multi method is-weekend(Saturday: --> True) { }
multi method is-weekend(Sunday: --> True) {}
multi method is-weekend(::?CLASS:D: --> False) { }
proto method days-til-weekend(::?CLASS:D: --> Int:D) {*}
# there is probably a better way to express this, but
# hopefully the concept is clear
multi method days-til-weekend(Monday: --> 4) {}
...
}
say Monday.is-weekend;
say Wednesday.days-til-weekend;
say Saturday.is-weekend;

Related

What is the difference between method call syntax `foo.method()` and UFCS `Foo::method(&foo)`?

Is there any difference in Rust between calling a method on a value, like this:
struct A { e: u32 }
impl A {
fn show(&self) {
println!("{}", self.e)
}
}
fn main() {
A { e: 0 }.show();
}
...and calling it on the type, like this:
fn main() {
A::show(&A { e: 0 })
}
Summary: The most important difference is that the universal function call syntax (UFCS) is more explicit than the method call syntax.
With UFCS there is basically no ambiguity what function you want to call (there is still a longer form of the UFCS for trait methods, but let's ignore that for now). The method call syntax, on the other hand, requires more work in the compiler to figure out which method to call and how to call it. This manifests in mostly two things:
Method resolution: figure out if the method is inherent (bound to the type, not a trait) or a trait method. And in the latter case, also figure out which trait it belongs to.
Figure out the correct receiver type (self) and potentially use type coercions to make the call work.
Receiver type coercions
Let's take a look at this example to understand the type coercions to the receiver type:
struct Foo;
impl Foo {
fn on_ref(&self) {}
fn on_mut_ref(&mut self) {}
fn on_value(self) {}
}
fn main() {
let reference = &Foo; // type `&Foo`
let mut_ref = &mut Foo; // type `&mut Foo`
let mut value = Foo; // type `Foo`
// ...
}
So we have three methods that take Foo, &Foo and &mut Foo receiver and we have three variables with those types. Let's try out all 9 combinations with each, method call syntax and UFCS.
UFCS
Foo::on_ref(reference);
//Foo::on_mut_ref(reference); error: mismatched types
//Foo::on_value(reference); error: mismatched types
//Foo::on_ref(mut_ref); error: mismatched types
Foo::on_mut_ref(mut_ref);
//Foo::on_value(mut_ref); error: mismatched types
//Foo::on_ref(value); error: mismatched types
//Foo::on_mut_ref(value); error: mismatched types
Foo::on_value(value);
As we can see, only the calls succeed where the types are correct. To make the other calls work we would have to manually add & or &mut or * in front of the argument. That's the standard behavior for all function arguments.
Method call syntax
reference.on_ref();
//reference.on_mut_ref(); error: cannot borrow `*reference` as mutable
//reference.on_value(); error: cannot move out of `*reference`
mut_ref.on_ref();
mut_ref.on_mut_ref();
//mut_ref.on_value(); error: cannot move out of `*mut_ref`
value.on_ref();
value.on_mut_ref();
value.on_value();
Only three of the method calls lead to an error while the others succeed. Here, the compiler automatically inserts deref (dereferencing) or autoref (adding a reference) coercions to make the call work. Also note that the three errors are not "type mismatch" errors: the compiler already tried to adjust the type correctly, but this lead to other errors.
There are some additional coercions:
Unsize coercions, described by the Unsize trait. Allows you to call slice methods on arrays and to coerce types into trait objects of traits they implement.
Advanced deref coercions via the Deref trait. This allows you to call slice methods on Vec, for example.
Method resolution: figuring out what method to call
When writing lhs.method_name(), then the method method_name could be an inherent method of the type of lhs or it could belong to a trait that's in scope (imported). The compiler has to figure out which one to call and has a number of rules for this. When getting into the details, these rules are actually really complex and can lead to some surprising behavior. Luckily, most programmers will never have to deal with that and it "just works" most of the time.
To give a coarse overview how it works, the compiler tries the following things in order, using the first method that is found.
Is there an inherent method with the name method_name where the receiver type fits exactly (does not need coercions)?
Is there a trait method with the name method_name where the receiver type fits exactly (does not need coercions)?
Is there an inherent method with the name method_name? (type coercions will be performed)
Is there a trait method with the name method_name? (type coercions will be performed)
(Again, note that this is still a simplification. Different type of coercions are preferred over others, for example.)
This shows one rule that most programmers know: inherent methods have a higher priority than trait methods. But a bit unknown is the fact that whether or not the receiver type fits perfectly is a more important factor. There is a quiz that nicely demonstrates this: Rust Quiz #23. More details on the exact method resolution algorithm can be found in this StackOverflow answer.
This set of rules can actually make a bunch of changes to an API to be breaking changes. We currently have to deal with that in the attempt to add an IntoIterator impl for arrays.
Another – minor and probably very obvious – difference is that for the method call syntax, the type name does not have to be imported.
Apart from that it's worth pointing out what is not different about the two syntaxes:
Runtime behavior: no difference whatsoever.
Performance: the method call syntax is "converted" (desugared) into basically the UFCS pretty early inside the compiler, meaning that there aren't any performance differences either.

strongly typed enum - `class` keyword optional?

In 'modern' C++ that suppports strongly typed enums: is the class keyword optional?
I saw code that defines enums like:
enum SomeEnum: unsigned int {
VAL1 = 0,
VAL2 = 1,
// ...
};
Is this a different thing, a sloppyness of the compiler (VS 2015 (MSVC 19)) or is the class keyword implicit if the enum is strongly typed?
The code in the question declares a normal unscoped enumeration, whose underlying type is however fixed. So it is different from enum class because it still does not introduce a scope for its enumerators.
Since c++11 even normal enums (which still exist) can accept an underlying type specification. See here.
enum-key attr(optional) identifier(optional) enum-base(optional)(C++11) { enumerator-list(optional) }
Emphasis mine
So it is a normal enum not a enum class but with a enum-base specification.
What you call "strongly typed enum" is really named scoped enumerations, and for those the class or struct keyword is mandatory.
Using the "inheritance" syntax is not part of scoped enumerations, they can be used for normal unscoped enumerations as well.

Reference to an instance method of a particular object breaks the type-safety in Java?

Does the notion of a reference to an instance method of a particular object break the type-safety in Java?
According to
https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
you can have a custom class ComparisonProvider that DOES not implement the Comparator interface, and still use an instance of this class as the second argument of the method
Arrays.sort(T[] a, Comparator c)
Sure, the implementation of your ComparisonProvider MUST have a method whose signature exactly matches the Comparator.compare() method, but that is still not an instance of Comparator, isn't it?
In essence, Java 8 allows us to use instances of classes as if they were implementing a particular interface, while actually they are not.
This means, that we are loosing Type-safety in Java, do we?
lambda expressions and method reference don't have a predefined type, they are poly expressions, as seen here. That means that their type is derived from the context in which they are used.
In your example these both would be legal for example:
BiFunction<Person, Person, Integer> biFun = myComparisonProvider::compareByName;
Comparator<Person> comp = myComparisonProvider::compareByName;
But at the same time you can't do:
Arrays.sort(pers, biFun);
When you actually try to sort the array like this:
Arrays.sort(pers, myComparisonProvider::compareByName);
At the bytecode level that is a Comparator:
// InvokeDynamic #0:compare:(LTest$ComparisonProvider;)Ljava/util/Comparator;
Also notice that this would print true:
Comparator<Person> comp = myComparisonProvider::compareByName;
System.out.println(comp instanceof Comparator); // true
You can enable a flag : -Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here
and look at what that method reference is transformed into:
final class Test$$Lambda$1 implements java.util.Comparator
and inside it there's the compare method implementation(I've simplified it and removed some of it's code to make it a little more obvious):
public int compare(java.lang.Object, java.lang.Object);
Code:
4: aload_1
5: checkcast // class Test3$Person
8: aload_2
9: checkcast // class Test$Person
12: invokevirtual Test$ComparisonProvider.compareByName:(Test$Person;Test$Person;)I
Java 8 allows us to use instances of classes as if they were implementing a particular interface, while actually they are not
Not exactly, it allows you to use a single method of some instance of a class as if it were implementing some functional interface.
And it doesn't add any functionality that didn't exist in Java 7 - it just gives you a short cut to writing that functionality.
For example, instead of:
Arrays.sort(someArray, someInstance::someMethod);
In Java 7 you could use anonymous class instance to write:
Arrays.sort(someArray, new Comparator<SomeType> () {
public int compare (SomeType one, SomeTypeTwo) {
return someInstance.someMethod(one,two);
}
});
As long as the instance method is accessible (i.e. public), you can use it as you see fit.
Comparator is a functional interface, which means that when requested you can pass an instance of a class implementing it, use a lambda expression that conforms to the type of single abstract method declared in it or use a method reference that also conforms to.
Java 8 Functional interface makes the difference. This tries to catch the concept of function. Afterall what is important in Comparator is not the type itself but the method (and its type) that should be provided at runtime. In pre Java 8 you need to provide a function object, while in Java 8 you can simply provide the function (just what is needed).
So for the type system everything is correct, provided that the lambdas or references you use are of the type of the method of the functional interface.

Liftable for function literal

Is there a way to make a Liftable for a functional literal (with 2.11)? If I have
case class Validator[T](predicate: T => Boolean)
val predicate = (s: String) => s.startsWith("Hi")
then I want to be able to quasiquote predicate too:
q"new Validator($predicate)"
I hoped to magically create a Liftable with an underscore. But that was a little too optimistic:
implicit def liftPredicate[T: Liftable](f: T => Boolean) =
Liftable[T => Boolean]{ f => q"$f(_)" }
I couldn't figure out from looking at StandardLiftables how I could solve this one.
Another way of looking at it:
Say I want to create instances from the following class at compile time with a macro:
abstract class ClassWithValidation {
val predicate: String => Boolean
def validate(s: String) = predicate(s)
}
and I retrieve a functional literal from somewhere else as a variable value:
val predicate = (s: String) => s.startsWith("Hi")
Then I want to simply quasiquote that variable into the construction:
q"""new ClassWithValidation {
val predicate = $predicate
// other stuff...
}"""
But it gives me this error:
Error:(46, 28) Can't unquote String => Boolean, consider providing an
implicit instance of Liftable[String => Boolean]
Normally I can just make such implicit Liftable for a custom type. But I haven't found a way doing the same for a functional literal. Is there a way to do this or do I need to look at it another way?
From what I understand, you're trying to go from a function to an abstract syntax tree that represents its source code (so that it can be spliced into a macro expansion). This is a frequent thing that people request (e.g. it comes up often in DSLs), but there's no straightforward way of achieving that in our current macro system.
What you can do about this at the moment is to save the AST explicitly when declaring a function and then load and use it in your macro. The most convenient way of doing this is via another macro: https://gist.github.com/xeno-by/4542402. One could also imagine writing a macro annotation that would work along the same lines.
In Project Palladium, there is a plan to save typechecked trees for every program being compiled. This means that there will most likely be a straightforward API, e.g. treeOf(predicate) that would automatically return abstract syntax tree comprising the source of the predicate. But that's definitely not something set in stone - we'll see how it goes, and I'll report back on the progress during this year's ScalaDays.

Is there a hook for when anonymous classes are assigned to a constant?

I've been practicing some Ruby meta-programming recently, and was wondering about assigning anonymous classes to constants.
In Ruby, it is possible to create an anonymous class as follows:
anonymous_class = Class.new # => #<Class:0x007f9c5afb21d0>
New instances of this class can be created:
an_instance = anonymous_class.new # => #<#<Class:0x007f9c5afb21d0>:0x007f9c5afb0330>
Now, when the anonymous class is assigned to a constant, the class now has a proper name:
Foo = anonymous_class # => Foo
And the previously created instance is now also an instance of that class:
an_instance # => #<Foo:0x007f9c5afb0330>
My question: Is there a hook method for the moment when an anonymous class is assigned to a constant?
There are many hooks methods in Ruby, but I couldn't find this one.
Let's take a look at how constant assignment works internally. The code that follows is extracted from a source tarball of ruby-1.9.3-p0. First we look at the definition of the VM instruction setconstant (which is used to assign constants):
# /insns.def, line 239
DEFINE_INSN
setconstant
(ID id)
(VALUE val, VALUE cbase)
()
{
vm_check_if_namespace(cbase);
rb_const_set(cbase, id, val);
INC_VM_STATE_VERSION();
}
No chance to place a hook in vm_check_if_namespace or INC_VM_STATE_VERSION here. So we look at rb_const_set (variable.c:1886), the function that is called everytime a constant is assigned:
# /variable.c, line 1886
void
rb_const_set(VALUE klass, ID id, VALUE val)
{
rb_const_entry_t *ce;
VALUE visibility = CONST_PUBLIC;
# ...
check_before_mod_set(klass, id, val, "constant");
if (!RCLASS_CONST_TBL(klass)) {
RCLASS_CONST_TBL(klass) = st_init_numtable();
}
else {
# [snip], won't be called on first assignment
}
rb_vm_change_state();
ce = ALLOC(rb_const_entry_t);
ce->flag = (rb_const_flag_t)visibility;
ce->value = val;
st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)ce);
}
I removed all the code that was not even called the first time a constant was assigned inside a module. I then looked into all the functions called by this one and didn't find a single point where we could place a hook from Ruby code. This means the hard truth is, unless I missed something, that there is no way to hook a constant assignment (at least in MRI).
Update
To clarify: The anonymous class does not magically get a new name as soon as it is assigned (as noted correctly in Andrew's answer). Rather, the constant name along with the object ID of the class is stored in Ruby's internal constant lookup table. If, after that, the name of the class is requested, it can now be resolved to a proper name (and not just Class:0xXXXXXXXX...).
So the best you can do to react to this assignment is to check the name of the class in a loop of a background worker thread until it is non-nil (which is a huge waste of resources, IMHO).
Anonymous classes don't actually get their name when they're assigned to a constant. They actually get it when they're next asked what their name is.
I'll try to find a reference for this. Edit: Can't find one, sorry.

Resources