Reuse parent symbols in child module - oop

I am seeking to re-use the same role/class names in a child module as in its parent. You know, like a specialization.
The aim is to be able to re-use the same script code for both the parent and child Series variants by simply changing use Dan to use Dan::Pandas at the top.
I am trying to stick to role rather than class compostion where I can so that the behaviours can be applied to other objects with eg. class GasBill does Series;
Here is the MRE:
me#ubuntu:~/spike# tree
.
├── lib
│   ├── Dan
│   │   └── Pandas.rakumod
│   └── Dan.rakumod
└── spike.raku
Dan.rakumod:
1 unit module Dan;
2
3 role Series is export {
4 method no { "no" }
5 }
Pandas.rakumod:
1 unit module Dan::Pandas;
2
3 use Dan;
4
5 role Series does Dan::Series is export {
6 method yo { "yo" }
7 }
spike.raku:
1 use lib './lib';
2 use Dan::Pandas;
3
4 my $s = Series.new; #version 1
5 #my $s = Dan::Pandas::Series.new; #version 2 "fqm"
6
7 say $s.no, $s.yo, $s.^name;
My version 1 says:
No appropriate parametric role variant available for 'Dan::Series':
Ambiguous call to '(Dan::Series)'; these signatures all match:
(::$?CLASS ::::?CLASS Mu $)
(::$?CLASS ::::?CLASS Mu $)
in block <unit> at spike.raku line 4
My version 2 says:
Could not find symbol '&Series' in 'Dan::Pandas'
in block <unit> at spike.raku line 5
I am trusting that raku does have a way to do this, but darned if I can work it out!

TL;DR You need a solution that avoids having two roles with the same full name.
Golf
role R {}
role R {}
R.new
displays:
No appropriate parametric role variant available for 'R':
Ambiguous call to '(R)'; these signatures all match:
(::$?CLASS ::::?CLASS Mu $)
(::$?CLASS ::::?CLASS Mu $)
(See Gut-referencing warning when composing stubbed role for a bit more discussion of the error message.)
A solution
Just Dan.
Dan.rakumod:
unit module Dan;
role Series is export { method no { "no" } }
spike.raku:
use lib '.';
use Dan;
my $s = Series.new;
.say for $s.?no, $s.?yo, $s.^name;
Running spike displays:
no
Nil
Dan::Series
Introduce Dan::Pandas.
Alter Dan so variant modules can use it without them importing Dan's unqualified Series symbol into their lexical scopes.
(Because otherwise Dan's unqualified Series symbol ends up being in their lexical scopes as well as their own unqualified Series symbol, and you get the "Ambiguous call" error.)
Dan:
unit module Dan;
role Series is export { method no { "no" } }
class Dan::Variant-Export-Dummy-Type is export(:Variant-Exports) {}
The change is the last line, a dummy declaration with a new export tag. (Introducing the new tag some cleaner way is left as an exercise for readers.)
Dan::Pandas:
unit module Dan::Pandas;
use Dan :Variant-Exports;
role Series does Dan::Series is export { method yo { "yo" } }
The change is using the new :Variant-Exports tag with the use Dan ... statement. This stops Dan's Series role being imported under that unqualified name into Dan::Pandas.
User programs will now work as expected/wanted.
Just change the use statement in spike.raku:
use lib '.';
use Dan::Pandas;
my $s = Series.new;
.say for $s.?no, $s.?yo, $s.^name;
Running with just this change for user programs:
no
yo
Dan::Pandas::Series
Note how there's no need for programs using using these modules to know about the :Variant-Exports tag. That's just an internal detail of the Dan module and the Dan::Pandas etc modules that lets them avoid the unintended role variant duplication problem shown at the start of this answer.

If I'm understanding correctly, you don't need/want to use the non-specialized role in the final module (that is, you aren't using the Series defined in Dan.rakumod in spike.raku – you're only using the specialized Series defined in Pandas.rakumod). Is that correct?
If so, the solution is simple: just don't export the Series from Dan.rakumod – it's still our scoped (the default for roles) so you can still use it in Pandas.rakumod exactly the way you currently do (Dan::Series). But, since it's not exported, you it won't create a name clash with the non-prefixed Series.

My Solution
Taking the advice of #codesections [that FQMs can be used without is export] and #raiph [that you can qualify the export with e.g. is export(:ALL)], then - yes - there is a neat way to do this.
viz. https://docs.raku.org/language/modules#Exporting_and_selective_importing
Turns out that this is low touch (just change two lines) and, as I originally hoped, something that raku designers have anticipated.
Here is the code from my OP adjusted...
Dan.rakumod:
1 unit module Dan;
2
3 role Series is export(:ALL) { #<== added the selective export
4 method no { "no" }
5 }
Pandas.rakumod (no change):
1 unit module Dan::Pandas;
2
3 use Dan;
4
5 role Series does Dan::Series is export {
6 method yo { "yo" }
7 }
spike.raku:
1 use lib './lib';
2 #use Dan::Pandas; #\ either of these work
3 use Dan :ALL; #/ <== use :ALL to get 'Series'
4
5 my $s = Series.new;
6
7 say $s.no, $s.yo, $s.^name; #No such method 'yo' if Pandas not used

Related

How do I generate numbered lists with pod?

Looking at https://docs.raku.org/language/pod#Lists. I don't see a way to create a numbered list:
one
three
four
Is there an undocumented way to do it?
There is not currently (as of January 2022) an implemented way to use ordered list in Pod6.
The historical design documents contain Pod6 syntax for ordered lists and, as far as I know, this remains something that we'd like to add. Once that syntax is implemented, you'll be able to write something like:
=item1 # Animal
=item2 # Vertebrate
=item2 # Invertebrate
=item1 # Phase
=item2 # Solid
=item2 # Liquid
=item2 # Gas
This would produce output along the lines of:
1. Animal
1.1 Vertebrate
1.2 Invertebrate
2. Phase
2.1 Solid
2.2 Liquid
2.3 Gas
(Though the exact syntax for rendering the list would be up to the implementation of the Pod renderer.)
But until that's implemented, there isn't any way to use Pod6 syntax to create an ordered list.
Edit:
I just checked the actual parsed Pod6, and it looks like (to my surprise) the ordered list syntax I showed above actually is parsed internally. For example, running say $=pod[5].raku with the Pod6 shows the following (based on the =item2 # Liquid line):
Pod::Item.new(level => 2, config => {:numbered(1)}, contents => [Pod::Block::Para.new(config => {}, contents => ["Liquid"])])
So the parsing work is in place; it's just the Pod::To::_ renderer that need to add support. (And there could even be some out there that have that support. I do know that neither Rakudo's Pod::To::Text nor Raku's Pod::To::HTML (v0.8.1) currently render ordered lists, however.)
Workarounds
Depending on the output formats you're targeting, you could of course write the ordered list yourself (pretty easy if you're rendering to plain text, more annoying to do if you're printing to HTML). This does, of course, sacrifice Pod6's multi-output-format support, which is one of its key features.
For a workaround that doesn't sacrifice Pod's multi-output nature, you'd probably want to look into manipulating/reformatting the Pod text programmatically. If you do so, the docs to start with are the Pod6 section on accessing Pod and the (unfortunately very short) section on the DOC phaser.
Just use a list and a loop?
my #list = [ (1, 2, 3), (1, 2, ),
[<a b c>, <d e f>],
[[1]]];
for #list -> #element {
say "{#element} → {#element.^name}";
for #element -> $sub-element {
say $sub-element;
}
}
# OUTPUT:
#1 2 3 → List
#1
#2
#3
#1 2 → List
#1
#2
#a b c d e f → Array
#(a b c)
#(d e f)
#1 → Array
#1

Cab Dafny use an imported ADT in a match command

Hi I am running into time out problems and am trying to decompose my file into different modules on the hope that a verified module will not have to be reverified, in VS code, when working on a module that imports it.
If any one knows if this is a reasonable way to avoid time out problems I would like to hear.
But the more basic problem I found is that once I import an ADT I can make use of in in if statements but not in match statements. See code below for an example. Any ideas on what I am doing wrong?
module inner {
datatype Twee = Node(value : int, left : Twee, right : Twee) | Leaf
function rot(t:Twee) :Twee
{
match t
case Leaf => t
case Node(v,l,r) => Node(v,r,l)
}
}
module outer {
import TL = inner
function workingIf(t:TL.Twee) :TL.Twee
{ if (t == TL.Leaf) then TL.Leaf else t }
function failingMatch(t:TL.Twee) :TL.Twee
{
match t
case TL.Leaf => t // error "darrow expected"
case TL.Node(v,l,r) => TL.Node(v,r,l)
}
}
Sorry for asking the question - the following worked.
function failingMatch(t:TL.Twee) :TL.Twee
{
match t
case Leaf => t
case Node(v,l,r) => TL.Node(v,r,l)
}
Well that worked but the following failed
function rotateLeft(t:TL.Twee) :TL.Twee
{
match t
case Leaf => t
case Node(v,Leaf,r) => TL.Node(v,TL.Leaf,r)
case Node(v,Node(vl,ll,rl),r) => TL.Node(vl,ll,TL.Node(v,rl,r))
}
The answer to the first question was given by James Wilcox and can be found in What are the relationships among imports, includes, and verification in Dafny?
but for convienience I repeat below:
"import has no direct influence on whether the imported module is verified or not. Modules in other files will not be verified unless their file is listed on the command line. Modules in the current file are always verified (whether or not they are imported by anyone)."
The main question I have raised in https://github.com/dafny-lang/dafny/issues/870
Many thanks to everyone - teaching how to use Dafny with out stack overflow would be so much harder.
Somewhat oddly, the constructor names that follow each case keyword are expected to be unqualified. They are looked up in the type of the expression that follows the match. It's quirky that qualified names are not allowed, and this is likely something that will be corrected in the future (I thought there was a Dafny issue on github about this, but I can't find it).

How to give names to MobX flows

How do I give a name to my flows?
I currently see messages in the console (using dev tools) like:
action '<unnamed flow> - runid: 3 - init'
index.js:1 action '<unnamed flow> - runid: 3 - yield 0'
My code (in typescript):
fetchMetricData = flow( function * (this: MetricDataStore) {
const responseJson:IMetrics[] = yield Http.post("/metrics");
this.metrics = responseJson;
});
According to following text found in MobX Api Reference · MobX page:
Tip: it is recommended to give the generator function a name, this is the name that will show up in dev tools and such
Unfortunately, this is the only way to set the name (I use LiveScript and can't set names to function expressions while defining it).
In your case, you can turn your unnamed function expression into a named one. If you ever face another situation where you can't, you could also use Object.defineProperty(myFunction, 'name', {value: 'myExplicitName'}).
You can find the culprit in the code: mobx/flow.ts at master · mobxjs/mobx.

Vue.js root variable

I am working on my own directory for my purchases of cryptocurrencies.
I am getting prices of BTC, ETH, and LTC via API, then I created a component for each of my punched coin, so then I want to calculate current price (ownedCoins * currentPrice).
So in my $root I have { eth: 324.233, btc: 2211.43, ltc: 41.341 }
Here is where I want to calculate it:
self.eur = response.data.sum[0].quantity * this.$root.ltc;
But I want to make this dynamic, so what I want to do is to create a dynamic variable. Something like that: self.eur = response.data.sum[0].quantity * this.$root.{this.coinName};
How would I do that?
I would read the State Management part of the VueJS docs then checkout the Vuex docs. Once your data store get even mildly more complex your method of managing it with your sample code will become overwhelming.
Your question doesn't have anything to do with vue, but just plain javascript. To access object variables in javascript you have 2 ways, using the dot notation or bracket notation (I call it array notation):
const car = { wheels: 4, seats: 5, horsepower: 145 };
console.log(car.wheels);
console.log(car['wheels']); //same result
So
this.$root[this.coinName];
will give you the result you are looking for.

Passing options to JS function with Amber

I'm trying to write the equivalent of:
$( "#draggable" ).draggable({ axis: "y" });
in Amber smalltalk.
My guess was: '#draggable' asJQuery draggable: {'axis' -> 'y'} but that's not it.
Not working on vanilla 0.9.1, but working on master at least last two months ago is:
'#draggable' asJQuery draggable: #{'axis' -> 'y'}
and afaict this is the recommended way.
P.S.: #{ 'key' -> val. 'key2' -> val } is the syntax for inline creation of HashedCollection, which is implemented (from the aforementioned two-month ago fix) so that only public (aka enumerable) properties are the HashedCollection keys. Before the fix also all the methods were enumerable, which prevented to use it naturally in place of JavaScript objects.
herby's excellent answer points out the recommended way to do it. Appearently, there is now Dictionary-literal support (see his comment below). Didn't know that :-)
Old / Alternate way of doing it
For historical reasons, or for users not using the latest master version, this is an alternative way to do it:
options := <{}>.
options at: #axis put: 'y'.
'#draggable' asJQuery draggable: options.
The first line constructs an empty JavaScript object (it's really an JSObjectProxy).
The second line puts the string "y" in the slot "axis". It has the same effect as:
options.axis = "y"; // JavaScript
Lastly, it is invoked, and passed as a parameter.
Array-literals vs Dictionaries
What you were doing didn't work because in modern Smalltalk (Pharo/Squeak/Amber) the curly-brackets are used for array-literals, not as an object-literal as they are used in JavaScript.
If you evaluate (print-it) this in a Workspace:
{ #elelemt1. #element2. #element3 }.
You get:
a Array (#elelemt1 #element2 #element3)
As a result, if you have something that looks like a JavaScript object-literal in reality it is an Array of Association(s). To illustrate I give you this snippet, with the results of print-it on the right:
arrayLookingLikeObject := { #key1 -> #value1. #key2 -> #value2. #key3 -> #value3}.
arrayLookingLikeObject class. "==> Array"
arrayLookingLikeObject first class. "==> Association"
arrayLookingLikeObject "==> a Array (a Association a Association a Association)"
I wrote about it here:
http://smalltalkreloaded.blogspot.co.at/2012/04/javascript-objects-back-and-forth.html