Enum in Modules - enums

I am trying to use enums inside modules but without success:
# module for testing enums
module EE
export EnumTest
#enum EnumTest uu ii dd
end # module
I did importall EE in the repl. After this I checked the presence of the enum values with instances(EE.EnumTest) with the result
(uu::EE.EnumTest = 0, ii::EE.EnumTest = 1, dd::EE.EnumTest = 2)
(as expected).
When I am trying to return/print the value with uu::EE.EnumTest it is just throwing an exception UndefVarError. I don't expect this. How to use the value?

That export statement in your module just makes the names you list available for use outside the module. You only listed EnumTest — the overall type of the enum — and none of the instances.
You can access the instances by fully-qualifying them with the module name (EE.uu) or by adding them to the export list (export EnumTest, uu, ii, dd) and using EE. Note that importall isn't needed here and is deprecated in favor of using in cases like these in 0.7.

Related

How to use a certain set of values for typing in Python

I need to specify a certain set of values as the expected return type for my function. Let's say there was defined some class called Scene which has attribute name which is supposed to be a string which may end only with "1K", "2K" or "4K". Now I want to write a function which takes this class as an argument and returns the last 2 characters of its name as a string. Is there a way to specify this function return type like a set of exact string values using built-in modules in Python 3.7.7? Something like this:
def scene_resolution(sc : Scene): -> any value in {'1K', '2K', '4K'}: # return type?
res = sc.name[-2:]
assert res in {'1K', '2K', '4K'}
return res
I know about using Literal from typing_extensions, but unfortunately it works only with Python 3.8 and higher, and the API of the soft I'm dealing with uses Python 3.7.7. I've also tried to make something with enum.Enum but could not make it work properly.
Do you have any suggestions?
UPD. The only way I found so far is to define some function that returns the set I need and use its name as expected return type. Not sure whether it is correct way and a good practice, but at least it works.

How are enums augmentable?

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;

JShell access to variables defined outside of jshell instance

From inside jShell script, is it possible to access or register variables that are defined in code that's also creating JShell?
Currently there seems to be no mechanism to either access or register a variable to Shell instance, or return none string types from inside JShell (like objects or lambda etc.)
ex:
import jdk.jshell.JShell;
import jdk.jshell.JShellException;
import jdk.jshell.SnippetEvent;
import java.util.List;
public class Main {
public static void main(String[] args) throws JShellException {
var localVar = 1;
JShell shell = JShell.create();
// How to register localVar variable with shell instance or access variables from scope
List events = shell.eval("var x = localVar;");
SnippetEvent event = events.get(0);
System.out.println("Kind: " + event.snippet().kind() + ", Value: " + event.value());
}
}
While you can't access local names like in your example, you can create a JShell instance that executes in the same JVM that created it. For this you would use the LocalExecutionControl. Using this execution control you could move localVar to a static field in your Main class and then access it from "inside" the JShell code with Main.localVar.
Unfortunately as the API is designed to support execution providers that could be in a different process or even a different machine, the return type is a string. If you are interested in a hack, the IJava jupyter kernel needed to an implementation of eval that returned an Object which ended up using an ExecutionControl implementation based on the DirectExecutionControl that stored the result of an eval call in a map and returned a unique id to reference that result. Then using the shell you would have to lookup the result from the id returned by eval (think of something like results.get(eval(sourceCode))). That implementation is on github in IJavaExecutionControl.java and IJavaExecutionControlProvider.java with a sample usage in CodeEvaluator.java#L72 if you are interested in taking any of it (MIT license).

nashorn replace Java.type with binding

To invoke Java from JS you can use Java.type. Is there a way to bind a java class in the Bindings?
So replace:
scriptEngine.eval("Java.type('my.own.AwesomeObj')");
with something like:
Bindings bindings = new SimpleBindings();
bindings.put("AwesomeObj", my.own.AwesomeObj.class);
scriptEngine.setBindings(bingings, ScriptContext.GLOBAL_SCOPE);
I am working on a framework where I want to make a lot of classes available for the js scripts, and preferably not use a string concatenation and an eval. Currently it throws an exception with message: AwesomeObj is not a function, what makes sense.
Nashorn distinguishes a type from a java.lang.Class instance, just like Java does (in Java language, my.own.AwesomeObj is a type, while my.own.AwesomeObj.class is an instance of java.lang.Class. You can use a type to access static members, or as a constructor. You can't use a Class object for that purpose. The bad news is, you can't directly obtain the object that Nashorn uses for representing types; it's an instance of jdk.internal.dynalink.beans.StaticClass and it lives in a restricted package. However, you can evaluate it in script with
engine.eval("Java.type('my.own.AwesomeObj')");
and put the result of that in the bindings. Incidentally, within Nashorn, if you put the Class object into bindings under name AwesomeObjClass, you can use the synthetic property .static to obtain the type, e.g.:
var AwesomeObj = AwesomeObjClass.static;
In this sense, .static on a Class object is the dual of .class on a type object (.static obviously doesn't exist in Java, where types aren't reified as runtime objects).
var stringType = Java.type("java.lang.String");
var stringClass = stringType.class
print(stringClass instanceof java.lang.Class); // true
print(stringType === stringClass.static); // true
Hope this helps.
since Java 9 you can use jdk.dynalink.beans.StaticClass.forClass as it is not internal anymore:
Bindings bindings = engine.createBindings();
bindings.put("AwesomeObj", StaticClass.forClass(my.own.AwesomeObj.class));
then you can utilize the binding in the JS code with :
var awesome = new AwesomeObj();
In your top-level script of your framework do:
var AwesomeObj = Java.type("my.own.AwesomeObj");

ipython parallel push custom object

I am unable to send object to direct view workers.
Here is what I want to do:
class Test:
def __init__(self):
self.id = 'ddfdf'
from IPython.parallel import Client
rc = Client()
dv = rc[:]
t = Test()
dv['t'] = t
print dv['t']
NameError: name 't' is not defined
This would work if I try to push pandas object or any of the build in objects.
What is the way to do it with custom object?
I tried:
dv['Test'] = Test
dv['t'] = t
print dv['t']
UnpicklingError: NEWOBJ class argument isn't a type object
For interactively defined classes (in __main__), you do need to push the class definition, or use dill. But even this doesn't appear to work for old-style classes, which is a bug in IPython's handling of old-style classes[1]. This code works fine if you use a new-style class:
class Test(object):
...
instead of on old-style class. Note that old-style classes are not available in Python 3.
It's generally a good idea to always use new-style classes anyway.

Resources