A singleton list of list is automatically decomposed - css

In SCSS, I have a mixin that takes a list and checks its length, as follows:
#mixin foo($list){
#debug length($list);
}
When I pass a list of more than two lists ($a, $a) as follows,
$a: (1, 2, 3);
#include foo(($a, $a));
the length function counts that there are two $a-s inside of ($a, $a), and returns the result:
DEBUG: 2
but when I pass a list that consists of a single list ($a) as follows,
#include foo(($a));
it seems that the list $a is decomposed, and the length function counts the three elements in $a instead of counting the number of $a-s in ($a), and returns the result:
DEBUG: 3
It does not make difference if I embed the list further. All of the following return the same result:
#include foo($a);
#include foo(($a));
#include foo((($a)));
Is this an expected feature? Why does this happen, and is there a way to return 1 in these cases?

In Sass, parentheses are used to indicate order of operations, not to indicate that you have a list with a single element.
In Sass 3.3, adding a trailing comma will automatically turn your value into a list:
$foo: 1, ;
What you may be wanting to do instead is have your mixin take a variable number of arguments and use them as a list. That would look like this:
#mixin foo($list...){
#debug length($list);
}
.foo {
#include foo(1);
}
.foo {
#include foo(1, 2);
}
.foo {
#include foo((1, 2));
}
The console gives the desired results:
DEBUG: 1
DEBUG: 2
DEBUG: 1
If you do this, however, the list must be the last argument of the mixin (or function).

Related

Modifying #content inside a SASS mixin [duplicate]

I run this Sass code:
$a: 1;
#if 2 + 2 == 4 {
$a: 2;
}
#debug $a;
I expect to see 2. The output, however, is:
Line 5 DEBUG: 1
I understand that Sass creates a new $a variable inside the #if scope. How can I change this behaviour and assign a value to the global $a?
I use Sass 3.4.0.
As you're using Sass 3.4+, you should append the !global flag to your variable declaration:
$a: 1;
#if 2 + 2 == 4 {
$a: 2 !global;
}
#debug $a; // will output 2
The original SASS_REFERENCE on variable declaration stated:
"Variables are only available within the level of nested selectors
where they're defined. If they're defined outside of any nested
selectors, they're available everywhere.
but the SASS_CHANGELOG of 3.4+ shows that this behaviour has changed:
All variable assignments not at the top level of the document are now
local by default. If there’s a global variable with the same name, it
won’t be overwritten unless the !global flag is used.
For example, $var: value !global will assign to $var globally. This behavior can be detected using feature-exists(global-variable-shadowing).
By trial-and-error, I found a solution: I have to add !global in the assignment.
$a: 1;
#if 2 + 2 == 4 {
$a: 2 !global;
}
#debug $a;

return multiple different values from single helper function?

I have a helper compare that returns a css class that simply highlights the text. "better" makes it green, "worse" colors it red. Basically the function compares 2 numbers (the compare function thats commented out does the same as the ternary below it). How can i compare multiple values in the same helper function? I know i could just create a bunch more helper functions and compare all the data 1 by 1, but im sure theres a better way. Heres what the template looks like :
Return the multiple values as an object from your helper then refer to the keys in your template.
js:
Template.myTemplate.helpers({
compare(){
return { key1: value1, key2: value2, ... keyN: valueN};
}
});
html:
{{compare.key1}} etc...
You'd have to pass them as arguments within the function definition itself, something like this should do the trick:
compare: function( number1, number2 ) {
return number1 > number 2 ? "better" : "worse";
}

Specman e: How to constrain 'all_different' to list of structs?

I have my_list that defined this way:
struct my_struct {
comparator[2] : list of int(bits:16);
something_else[2] : list of uint(bits:16);
};
...
my_list[10] : list of my_struct;
It is forbidden to comparators at the same index (0 or 1) to be the same in all the list. When I constrain it this way (e.g. for index 0):
keep my_list.all_different(it.comparator[0]);
I get compilation error:
*** Error: GEN_NO_GENERATABLE_NOTIF:
Constraint without any generatable element.
...
keep my_list.all_different(it.comparator[0]);
How can I generate them all different? Appreciate any help
It also works in one go:
keep for each (elem) in my_list {
elem.comparator[0] not in my_list[0..max(0, index-1)].apply(.comparator[0]);
elem.comparator[1] not in my_list[0..max(0, index-1)].apply(.comparator[1]);
};
When you reference my_list.comparator it doesn't do what you think it does. What happens is that it concatenates all comparator lists into one bit 20 element list. Try it out by removing your constraint and printing it:
extend sys {
my_list[10] : list of my_struct;
run() is also {
print my_list.comparator;
};
};
What you can do in this case is construct your own list of comparator[0] elements:
extend sys {
comparators0 : list of int;
keep comparators0.size() == my_list.size();
keep for each (comp) in comparators0 {
comp == my_list.comparator[index * 2];
};
keep comparators0.all_different(it);
// just to make sure that we've sliced the appropriate elements
run() is also {
print my_list[0].comparator[0], comparators0[0];
print my_list[1].comparator[0], comparators0[1];
print my_list[2].comparator[0], comparators0[2];
};
};
You can apply an all_different() constraint on this new list. To make sure it's working, adding the following constraint should cause a contradiction:
extend sys {
// this constraint should cause a contradiction
keep my_list[0].comparator[0] == my_list[1].comparator[0];
};

How to export Rcpp Class method with default arguments

I have a c++ class myClass which has a method foo(int x=0) and it has a parameter x with default value = 0. The c++ class could be exported to R by
RCPP_MODULE(my_module) {
class_< myClass >( "myClass" )
.constructor()
.method( "foo", &myClass::foo )
;
}
However, in R, I am not able to call myClass$foo without specifying the value of x.
I have to specify the value of x regardless the default value.
So my question is how to export Rcpp class method with default arguments. I tried to search it over the internet. The closest thing that I found was
using namespace Rcpp;
double norm( double x, double y ) { return sqrt( x*x + y*y );
}
RCPP_MODULE(mod_formals2) {
function("norm", &norm,
}
But it doesn't work in my case.
I had the same problem recently. After looking at the source file of rcpp handling the classes (~/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/module/class.h in my setup) I don't think that it is currently possible.
The best workaround I came up with was to create a wrapper in R to handle the default arguments.
Here is a full example demonstrating how to do it. I defined a simple function that accepts 3 arguments and outputs their sum. The second and third arguments are optional and set by default to 10 and 100.
mwe.cpp
#include <Rcpp.h>
class MWE {
public:
int sum_them(int mandatory_arg,
int optional_arg1,
int optional_arg2)
{
return (mandatory_arg+optional_arg1+optional_arg2);
}
};
RCPP_MODULE(mod_mwe) {
Rcpp::class_<MWE>( "MWE" )
.constructor()
.method("sum_them", &MWE::sum_them)
;
}
mwe.R
require('Rcpp')
# source the C++ code
sourceCpp('mwe.cpp')
# create an instance of the class:
my_mwe = new(MWE)
# assign a wrapper with default arguments to the instance:
assign('sum_them_wrapper',
function(mandatory_arg,
optional_arg1=10,
optional_arg2=100) {
return(my_mwe$sum_them(mandatory_arg, optional_arg1, optional_arg2))
},
envir = my_mwe
)
This outputs the expected result:
> my_mwe$sum_them_wrapper(3, optional_arg2=500)
[1] 513

Building a variadic mixin in LESS

I am trying to make a variadic mixin in LESS. To this end I use the following syntax for my mixin :
.mixin (#a; #rest...) {
// #rest is bound to arguments after #a
// #arguments is bound to all arguments
}
But I don't know how to manipulate #rest and read to the last parameters of the mixin.
This is my code :
.color () { }
.color (#shade) {
#id {
background-color : rgb(#shade, #shade, #shade);
}
}
.color (#shade, #rest...) {
#id {
background-color : rgb(#shade, #shade, #shade);
}
.color(#rest);
}
.color(200, 160);
As you guess, this mixin should examinate the entire list of parameters, and colour the background of my <div id="id"> with the shade of grey corresponding to the last parameter of the mixin (in this case, rgb(160, 160, 160)).
But when I compile this code with less-1.4.1.js, I get the following error :
SyntaxError: error evaluating function `rgb`:
color functions take numbers as parameters
So how to access to the second, third, fourth... parameters of the mixin ?
Thanks a lot for your advices, and have a nice week-end !
EDIT
This works perfectly, thanks a lot !
However I would like to ask an other question. Let's say that my mixin is variadic to the extent that it requires at least one parameter which has nothing to do with the rest of the arguments (e.g. a string or an other number), but which has to be processed, so that possible calls to the previous mixin could be :
.color("first argument", 200, 160);
.color(-42, 200, 160);
.color(3, 200, 160); // 3 doesn't need to be processed in the loop
In other words, the .loop should examinate all the parameters of the mixin starting from the second and apply a different process to the first argument. So I need to change the skeleton of the mixin into something like this :
.color(...) {
...; // Handling the first parameter
.loop (#arguments); // Handling the rest of the parameters
}
But in your solution, the variable #arguments contains the entire list of arguments, including the first. How to exclude it from the list, without playing on isnumber() ?
I precise that actually in my project, each of the parameters starting from the second are processed, so that :
.loop(#list, #index: 1, #shade: NULL) when not (isnumber(#list)) and (isnumber(extract(#list, #index))) {
.loop(#list, (#index + 1), extract(#list, #index));
}
becomes
.loop(#list, #index: 1, #shade: NULL) when not (isnumber(#list)) and (isnumber(extract(#list, #index))) {
.loop(#shade);
.loop(#list, (#index + 1), extract(#list, #index));
}
and this process doesn't consist in simply changing the background color of a fixed <div> ;) But I wanted to simplify my question.
Thanks a lot for your answers and precious advices !
Edit, again : what you recommend to me works perfectly, Martin. Thanks again !
Less gets confused with your second and third .color mixin, as they can both take just one argument, and if #rest is passed to the mixin as an argument and is not numeric (i.e. a list or empty) it causes more problems. Also #rest... and ... are tricky with multiple mixins with the same name - it is better to pass the arguments to another set of mixins (as a list to a single argument) and then switch between them using guards or the number of arguments they can take.
I would structure the mixins a bit differently (and add a helper mixin .loop that does the looping according to what is passed to .color).
The two mixins would then work like this:
.color: passes all arguments in #arguments to a single argument in mixin .loop
.loop: if the argument is neither a list nor a numeric value -> no output
.loop: if multiple arguments in a list -> loop through the list until you reach the last numeric value (or rather stops when it meets the first nonnumeric argument)
.loop: when reached the last parameter return output based on its value
.loop: if parameter is a single value -> return output based on the single parameter
in Less this could be done like this:
.loop(#list, #index: 1, #shade: NULL) when not (isnumber(#list)) and not (isnumber(extract(#list, #index))) and not (isnumber(#shade)) {}
.loop(#list, #index: 1, #shade: NULL) when not (isnumber(#list)) and (isnumber(extract(#list, #index))) {
.loop(#list, (#index + 1), extract(#list, #index));
}
.loop(#list, #index: 1, #shade) when not (isnumber(#list)) and not (isnumber(extract(#list, #index))) {
.loop(#shade);
}
.loop(#shade) when (isnumber(#shade)){
#id {
background-color: rgb(#shade, #shade, #shade);
}
}
.color (...) {
.loop(#arguments);
}
and if you call now something like this:
.color(120,160);
the output CSS will look like this:
#id {
background-color: #a0a0a0;
}
which corresponds to the value of the last argument -> rgb(160,160,160)
This now has an output only for the last argument in the list. If you want to do something for each argument, you do so in the second .loop mixin (the actual loop) and can get rid of the third one that is used only to separate the last iteration step from the rest of the loop.
Edit:
To your additional question "How to deal differently with certain arguments and what to do when they are not numeric?" - > General answer: you can always adjust the guards, and add additional mixins for the specific cases.
For example, if you want to treat the first argument (or any argument) differently using the .loop, you can add an additional .loop mixin - like this:
.loop(#list) when not (isnumber(#list)) {
/* do something with the first argument */
#first_argument: extract(#list, 1);
/* start the loop at the second argument:*/
.loop(#list, 2);
}
with the rest left as is, this should do what you want:
save your "first argument" from the #arguments into a variable (or you can do with it whatever you want)
start the loop at the second argument and continue until it reaches the last numeric argument (as shown above)
As said before, this is just an example illustrating how to do what you asked ... but you will have to play with it and design the guards and mixins accordingly to your desired outcome and your specific problems.
In the loop you can do something to each argument ... and you can do different things to numeric and nonnumeric arguments (you just need to adjust the conditions in the guards), you can check also if the arguments have specific units and so on. All this is simple as you are merely iterating through a list using the extract() function and incrising the #index variable.
In the case the first argument / first couple arguments have a specific assignment you can use #rest in the same way as I show with #arguments and do something with the first argument already in the .color mixin before you send the #rest to the .loop. You would do something like this:
.color (#first, #rest...) {
/* do something with the first argument */
#first_argument: #first;
/* send the rest to the loop */
.loop(#rest);
}

Resources