Wrong Signature.ACCEPTS after .wrap sub - raku

After I wrap a sub the signature do not ACCEPTS a Capture accepted before wrapping.
sub wr(:$a) {say $a};
my $sig-before = &wr.signature;
say $sig-before; # (:$a)
say %(:a(3)) ~~ $sig-before; # True
&wr.wrap(-> |c {callsame(c)});
my $sig-after = &wr.signature;
say $sig-after; # (:$a)
say %(:a(3)) ~~ $sig-after; # False
say %(:a(3)) ~~ $sig-before; # False
say $sig-before.WHICH, ' ', $sig-after.WHICH; # Signature|140466574255752 Signature|140466574255752
say $sig-before eq $sig-after; # True
say %(:a(3)).Capture ~~ $sig-after; # 'Cannot invoke object with invocation handler in this context'
say $sig-after.ACCEPTS(%(:a(3)).Capture); # 'Cannot invoke object with invocation handler in this context'
I see in Rakudo code:
multi method ACCEPTS(Signature:D: Capture $topic) {
nqp::p6bool(nqp::p6isbindable(self, nqp::decont($topic)));
}
Probably it is a bug? Or how can I workaround that behavior if it is expected and how can I understand in run time that I have do the workaround in concrete case?

2022 update Works as #MikhailKhorkov expected in a recent Rakudo (v2022.02):
(:$a)
True
(:$a)
True
True
Signature|4343308333200 Signature|4343308333200
True
True
True
Original answer
Probably it is a bug?
I've been wrong before when I call something a bug but I'd say something in there is a bug, even if it's just a Less Than Awesome error message bug.
I think wrap has relatively few roast tests (many matches are false positives; search for wrap( or wrap: in the results). One key thing to do here if you want to use wrap is add a roast test covering what we want it to do here that it is not doing correctly (assuming it's not just a Less Than Awesome error message).
I think wrap is one of the most fragile official P6 features:
new/open/stalled bugs in RT Perl 6 queue matching 'wrap'.
new/open/stalled bugs in RT Perl 6 queue matching 'Cannot invoke object with invocation handler in this context'.
open rakudo repo issues matching 'wrap'.
open rakudo repo issues matching 'Cannot invoke object with invocation handler in this context'.

Related

make-basic.publish with default value for exchange gives exception error: bad argument

I'm trying to follow the RabbitMq hello world tutorial in Lisp Flavoured Erlang. The tutorial is for Elixir, with the help of Erlang RabbitMQ client user guide I try to translate the steps to LFE. To publish a message, I need a basic.publish-record.
When I try:
(make-basic.publish routing_key #"hello")
(in a function in my lfe-file, which I call from the REPL).
This results in:
** exception error: bad argument
in min_make_record:not-working-queue-declare/0 (/home/.../min_make_record/_build/default/lib/amqp_client/include/amqp_client.hrl, line 26)
When I call make-basic.publish with the same arguments from the REPL, it returns the record as expected.
The error appears to be related to the default argument for exchange. The record is defined in rabbit_common/include/rabbit_framing.hrl as:
-record('basic.publish', {ticket = 0, exchange = <<"">>, routing_key = <<"">>, mandatory = false, immediate = false}).
The following do work:
make-basic.publish from the REPL
passing an argument for both exchange and routing_key:
(make-basic.publish exchange #"" routing_key #"hello")
Removing exchange and routing_key from the record (or a copy of it) and then calling make-basic.publish
(make-amqp_params_network) from amqp_client.hrl this record also has binary strings with defaults:
-record(amq_params_network, {username = <<"guest">>, password=<<"guest">>, virual_host=<<"/">>, host="localhost", port=undefined, channel_max=2047, frame_max=0, heartbeat=10, connection_timeout=60000, ssl_options=none, auth_mechanisms=[fun amqp_auth_mechanisms:plain/3, fun amqp_auth_mechanisms:amqplain/3], client_properties = []¸socjet_options=[]}).
Is there a difference in the syntactic sugar LFE generates for direct includes and transitive includes?
Or does the point in the name cause problems?
I tried:
starting amqp_client (via .app.src): amqp_client must be started otherwise there is an other error.
including both amqp_client.hrl and rabbit_framing.hrl from my lfe-file: this results in lots of "record ... already defined"-errors.
(Adding an include guard to rabbit_framing.hrl does not help)

WebSphere wsadmin testConnection error message

I'm trying to write a script to test all DataSources of a WebSphere Cell/Node/Cluster. While this is possible from the Admin Console a script is better for certain audiences.
So I found the following article from IBM https://www.ibm.com/support/knowledgecenter/en/SSAW57_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/txml_testconnection.html which looks promising as it describles exactly what I need.
After having a basic script like:
ds_ids = AdminConfig.list("DataSource").splitlines()
for ds_id in ds_ids:
AdminControl.testConnection(ds_id)
I experienced some undocumented behavior. Contrary to the article above the testConnection function does not always return a String, but may also throw a exception.
So I simply use a try-catch block:
try:
AdminControl.testConnection(ds_id)
except: # it actually is a com.ibm.ws.scripting.ScriptingException
exc_type, exc_value, exc_traceback = sys.exc_info()
now when I print the exc_value this is what one gets:
com.ibm.ws.scripting.ScriptingException: com.ibm.websphere.management.exception.AdminException: javax.management.MBeanException: Exception thrown in RequiredModelMBean while trying to invoke operation testConnection
Now this error message is always the same no matter what's wrong. I tested authentication errors, missing WebSphere Variables and missing driver classes.
While the Admin Console prints reasonable messages, the script keeps printing the same meaningless message.
The very weird thing is, as long as I don't catch the exception and the script just exits by error, a descriptive error message is shown.
Accessing the Java-Exceptions cause exc_value.getCause() gives None.
I've also had a look at the DataSource MBeans, but as they only exist if the servers are started, I quickly gave up on them.
I hope someone knows how to access the error messages I see when not catching the Exception.
thanks in advance
After all the research and testing AdminControl seems to be nothing more than a convinience facade to some of the commonly used MBeans.
So I tried issuing the Test Connection Service (like in the java example here https://www.ibm.com/support/knowledgecenter/en/SSEQTP_8.5.5/com.ibm.websphere.base.doc/ae/cdat_testcon.html
) directly:
ds_id = AdminConfig.list("DataSource").splitlines()[0]
# other queries may be 'process=server1' or 'process=dmgr'
ds_cfg_helpers = __wat.AdminControl.queryNames("WebSphere:process=nodeagent,type=DataSourceCfgHelper,*").splitlines()
try:
# invoke MBean method directly
warning_cnt = __wat.AdminControl.invoke(ds_cfg_helpers[0], "testConnection", ds_id)
if warning_cnt == "0":
print = "success"
else:
print "%s warning(s)" % warning_cnt
except ScriptingException as exc:
# get to the root of all evil ignoring exception wrappers
exc_cause = exc
while exc_cause.getCause():
exc_cause = exc_cause.getCause()
print exc_cause
This works the way I hoped for. The downside is that the code gets much more complicated if one needs to test DataSources that are defined on all kinds of scopes (Cell/Node/Cluster/Server/Application).
I don't need this so I left it out, but I still hope the example is useful to others too.

swi-prolog wait_for_input on files where the stream is at the end of the file

I don't understand why wait_for_input is not waiting when the end of a file is reached. I tried it on Mac OS X with swi-prolog 7.6.0 and Red Hat linux 6, with swi-prolog 5.7.11. I open a stream to a file that contains the single line "f(1).", without the quotes. I get the following behavior, where wait_for_input returns but reading the stream gives end_of_file.
?- open('file.prolog',read,InStrm,[alias(instrm),eof_action(reset)]).
InStrm = instrm.
?- wait_for_input([instrm],RL,15).
RL = [instrm].
?- read(instrm,Trm).
Trm = f(1).
?- wait_for_input([instrm],RL,15).
RL = [instrm].
?- read(instrm,Trm).
Trm = end_of_file.
I use eof_action(reset) so that if another process appends to the file, the reader will get the new data.
wait_for_input/3 is not really supposed to be used for your use case.
According to Swi-Prolog's documentation, wait_for_input/3 by default uses "poll" system call (when available, which should be true in your case):
When available, the implementation is based on the poll() system call.
"poll" system call, in turn, always succeeds immediately for regular files:
Regular files shall always poll TRUE for reading and writing.
See following links for further information:
http://www.swi-prolog.org/pldoc/doc_for?object=wait_for_input/3
https://linux.die.net/man/3/poll

error : can't read .... no such variable in TCL script using "after"

I am working in a TCL automation environent at my workplace.
I'm trying to run a delayed command in my script using "after".
The problem i encounter is that when i try to specify commands with variables inside a code block under an "after" , the vars are not recognized and i get an error message.
I'll quote the relevant parts of the code.
proc test_script1 {{bh0 0} ...more vars....} {
.
.
.
after [expr 20000] {
set some_value[ ns1::probe_TCP_connections $bh0 $main_duration 1 15] }
puts "the value i got is $some_value"
}
And i seem to get an error:
can't read "some_value": no such variable
Can anyone suggets what is the problem , and how to oversome it?
thx
You can capture the values of local variables with the help of apply (and it's advisable to use list to build callbacks when they get even slightly non-trivial). Since the body of an apply is a lambda expression with its own scope — a little nameless procedure — you have to use global in it to access state that will persist, and in any case after callbacks are called from the global namespace always (since the mechanism doesn't know how to keep arbitrary stack frames around for the duration of the asynchronous operation).
after 20000 [list apply {{bh0 main_duration} {
global some_value
set some_value [ns1::probe_TCP_connections $bh0 $main_duration 1 15]
}} $bh0 $main_duration]
global some_value
vwait some_value
puts "The value was changed to $some_value"
It's possible to get even more sophisticated, especially in Tcl 8.6 which has a coroutine system that can be used to hide the complexity of using continuation passing style programming.
Here is a proc that will do something similar to what you're trying to do:
proc foo {} {
# Make 'a' available to both the global scope and local scope
global a
# This is to check the current level
puts "Current level: [info level]"
# The command to be run in 500 ms, and I have added another check for the level
after 500 {puts "Current level: [info level]"; set a 100}
# Wait for further execution until the global variable 'a' changes
vwait a
# Prints a
puts "Value of \$a: $a"
}
The output of the above will be:
Current level: 1
# After 500 ms, the below will print
Current level: 0
Value of $a: 100
When you use after, the variable a is being created in the global scope, that is not accessible to the proc unless explicitly given access. One of the simplest ways is to first make sure that a within the proc is accessible both globally and locally, with global (level 0).

What's the equivalent of moment-yielding (from Tornado) in Twisted?

Part of the implementation of inlineCallbacks is this:
if isinstance(result, Deferred):
# a deferred was yielded, get the result.
def gotResult(r):
if waiting[0]:
waiting[0] = False
waiting[1] = r
else:
_inlineCallbacks(r, g, deferred)
result.addBoth(gotResult)
if waiting[0]:
# Haven't called back yet, set flag so that we get reinvoked
# and return from the loop
waiting[0] = False
return deferred
result = waiting[1]
# Reset waiting to initial values for next loop. gotResult uses
# waiting, but this isn't a problem because gotResult is only
# executed once, and if it hasn't been executed yet, the return
# branch above would have been taken.
waiting[0] = True
waiting[1] = None
As it is shown, if in am inlineCallbacks-decorated function I make a call like this:
#inlineCallbacks
def myfunction(a, b):
c = callsomething(a)
yield twisted.internet.defer.succeed(None)
print callsomething2(b, c)
This yield will get back to the function immediately (this means: it won't be re-scheduled but immediately continue from the yield). This contrasts with Tornado's tornado.gen.moment (which isn't more than an already-resolved Future with a result of None), which makes the yielder re-schedule itself, regardless the future being already resolved or not.
How can I run a behavior like the one Tornado does when yielding a dummy future like moment?
The equivalent might be something like a yielding a Deferred that doesn't fire until "soon". reactor.callLater(0, ...) is generally accepted to create a timed event that doesn't run now but will run pretty soon. You can easily get a Deferred that fires based on this using twisted.internet.task.deferLater(reactor, 0, lambda: None).
You may want to look at alternate scheduling tools instead, though (in both Twisted and Tornado). This kind of re-scheduling trick generally only works in small, simple applications. Its effectiveness diminishes the more tasks concurrently employ it.
Consider whether something like twisted.internet.task.cooperate might provide a better solution instead.