Is there a difference between
myProperty: myFunction()
or
myProperty: { ... }
or is the latter the same as the former?
They are basically the same. In the latter version, any explicit return gives the property its value. If there is no return, the last expression in the block becomes the property value.
I prefer the first version when working exclusively with a JS expression and use the second form where the calculation takes some imperative logic. I always use explicit returns in the second form.
Related
I started working with CSS variables to try out making a modular sizing scale. But I quickly ran into problems where CSS values were ignored but I did not see any indication on what was wrong.
Let's see a minimal reproduction of the problem:
:root {
--ratio: 1.25;
--font-size-medium-heading: calc(var(--ratio) * 1rem);
--font-size-large-heading: calc(var(--font-medium-heading) * var(--ratio)); /* note the typo in the var */
}
h1 {
font-size: var(--font-size-large-heading);
}
I made a typo on purpose to see what will happen (I have left out -size from the variable name). Since my heading got mini I tried querying the value of my new CSS variable:
getComputedStyle(document.documentElement).getPropertyValue('--font-size-large-heading') === ''
It returned an empty string.
Let's head to Chrome's style inspector and see if I get the warning sign ⚠️:
MDN advises to use a CSS validator. So let's try out this: https://jigsaw.w3.org/css-validator/validator
My guess is that this validator is not really up-to-date (if anyone using it still).
Update
I understood that according to the spec it is a valid statement, but the computed-time value of it is invalid. I want to know about these as it is just hiding the true problem in a very frequent mistake (if you have ever spent a day on finding out that Angular expected a "'thing'" instead of "thing" in a template, you will understand how bad is having no output about invalid values).
Is there a way to get an error output about computed-time invalid CSS vars and calc values?
First the spec
If a property contains one or more var() functions, and those functions are syntactically valid, the entire property’s grammar must be assumed to be valid at parse time. It is only syntax-checked at computed-value time, after var() functions have been substituted.
This why you don't see the yellow triangle in chrome devtool, because syntax wise it's valid.
From the spec focus on the fourth rule
Otherwise, the property containing the var() function is invalid at computed-value time
Also
A declaration can be invalid at computed-value time if it contains a var() that references a custom property with the guaranteed-invalid value
The third line in your code contains a var() that references a css variable with the guaranteed-invalid value
Why?
The initial value of a custom property is a guaranteed-invalid value. As defined in § 3 Using Cascading Variables: the var() notation, using var() to substitute a custom property with this as its value makes the property referencing it invalid at computed-value time.
A none-existing css variables basically creates it and it's initial value is the guaranteed-invalid value.
What's that initial value compute to ?
This value serializes as the empty string, but actually writing an empty value into a custom property, like --foo: ;, is a valid (empty) value, not the guaranteed-invalid value. If, for whatever reason, one wants to manually reset a variable to the guaranteed-invalid value, using the keyword initial will do this.
This is why getComputedStyle(document.documentElement).getPropertyValue('--font-size-large-heading') returns an "empty string" (guaranteed-invalid value)
I'm new to meteor, and I've followed different tutorials that explain and use things differently.
There seems to be two ways of processing an event. For example, if I want to manage a click on a tag, both of the following methods work :
This one is present on the hello world meteor app
'click p'(event, instance) {
}
This one is the one used in the tutorial.
'click p': function(event){
}
Both work perfectly and if I use both the last one will be effective. The weird thing is the color is not the same (on sublime text), the second has usual js colors but the first one is only green, orange, and everything else is white (on monokai).
I'm tempted to use the second one for better visibility, but I know I should not make that choice base on that. Which one is correct, and when ?
Bottom line: it doesn't really matter if you only need the event.
There are 2 syntactic differences between the functions, but there is no substantial difference:
The notation that you are using:
funcName(arg1, arg2)
vs
funcName: function(arg1, arg2)
The highlighting coloration difference you see in your editor is probably related to the shorthand notation. This shorthand notation is a feature of ES2015, the relatively new version of JS, and both are functionally identical. It is just syntactic sugar.
The arity (number of arguments).
The function is used as an event handler as a callback. Due to the dynamic nature of JavaScript, any function can be called with any number of parameters. The parameters are being assigned to arguments based on the function's definition, and are also dynamically available to the called function via the arguments pseudo-array.
The callback will always be called with 2 parameters. In the version with 1 argument, the second parameter will not be bound to any identifier within the function. You can omit the second argument if you don't need the template instance.
Can a pure function use a private constant variable inside the same class?
for example:
class TimesThousand {
const CONSTANT = 1000;
function calculate(number) {
return number * CONSTANT;
}
}
can calculate() be considered as a pure function?
A pure function is pure, when the return value is only determined by its input values, without any observable side effects.
So your function is pure. Since the value of CONSTANT is (as the name suggests) constant, the output is purely determined by the input.
From Wikipedia:
a function may be considered a pure function if both of the following statements about the function hold:
The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices.
Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.
Can someone tell me the exact difference between node() and element() types in XQuery? The documentation states that element() is an element node, while node() is any node, so if I understand it correctly element() is a subset of node().
The thing is I have an XQuery function like this:
declare function local:myFunction($arg1 as element()) as element() {
let $value := data($arg1/subelement)
etc...
};
Now I want to call the function with a parameter which is obtained by another function, say functionX (which I have no control over):
let $parameter := someNamespace:functionX()
return local:myFunction($parameter)
The problem is, functionX returns an node() so it will not let me pass the $parameter directly. I tried changing the type of my function to take a node() instead of an element(), but then I can’t seem to read any data from it. $value is just empty.
Is there some way of either converting the node to an element or should am I just missing something?
EDIT: As far as I can tell the problem is in the part where I try to get the subelement using $arg1/subelement. Apparently you can do this if $arg1 is an element() but not if it is a node().
UPDATE: I have tested the example provided by Dimitre below, and it indeed works fine, both with Saxon and with eXist DB (which is what I am using as the XQuery engine). The problem actually occurs with the request:get-data() function from eXist DB. This function gets data provided by the POST request when using eXist through REST, parses it as XML and returns it as a node(). But for some reason when I pass the data to another function XQuery doesn’t acknowledge it as being a valid element(), even though it is. If I extract it manually (i.e. copy the output and paste it to my source code), assign it to a variable and pass it to my function all goes well. But if I pass it directly it gives me a runtime error (and indeed fails the instance of test).
I need to be able to either make it ignore this type-check or “typecast” the data to an element().
data() returning empty for an element just because the argument type is node() sounds like a bug to me. What XQuery processor are you using?
It sounds like you need to placate static type checking, which you can do using a treat as expression. I don't believe a dynamic test using instance of will suffice.
Try this:
let $parameter := someNamespace:functionX() treat as element()
return local:myFunction($parameter)
Quoting from the 4th edition of Michael Kay's magnum opus, "The treat as operator is essentially telling the system that you know what the runtime type is going to be, and you want any checking to be deferred until runtime, because you're confident that your code is correct." (p. 679)
UPDATE: I think the above is actually wrong, since treat as is just an assertion. It doesn't change the type annotation node(), which means it's also a wrong assertion and doesn't help you. Hmmm... What I really want is cast as, but that only works for atomic types. I guess I'm stumped. Maybe you should change XQuery engines. :-) I'll report back if I think of something else. Also, I'm curious to find out if Dimitre's solution works for you.
UPDATE #2: I had backpedaled here earlier. Can I backpedal again? ;-) Now my theory is that treat as will work based on the fact that node() is interpreted as a union of the various specific node type annotations, and not as a run-time type annotation itself (see the "Note" in the "Item types" section of the XQuery formal semantics.) At run time, the type annotation will be element(). Use treat as to guarantee to the type checker that this will be true. Now I wait on bated breath: does it work for you?
EXPLANATORY ADDENDUM: Assuming this works, here's why. node() is a union type. Actual items at run time are never annotated with node(). "An item type is either an atomic type, an element type, an attribute type, a document node type, a text node type, a comment node type, or a processing instruction type."1 Notice that node() is not in that list. Thus, your XQuery engine isn't complaining that an item has type node(); rather it's complaining that it doesn't know what the type is going to be (node() means it could end up being attribute(), element(), text(), comment(), processing-instruction(), or document-node()). Why does it have to know? Because you're telling it elsewhere that it's an element (in your function's signature). It's not enough to narrow it down to one of the above six possibilities. Static type checking means that you have to guarantee—at compile time—that the types will match up (element with element, in this case). treat as is used to narrow down the static type from a general type (node()) to a more specific type (element()). It doesn't change the dynamic type. cast as, on the other hand, is used to convert an item from one type to another, changing both the static and dynamic types (e.g., xs:string to xs:boolean). It makes sense that cast as can only be used with atomic values (and not nodes), because what would it mean to convert an attribute to an element (etc.)? And there's no such thing as converting a node() item to an element() item, because there's no such thing as a node() item. node() only exists as a static union type. Moral of the story? Avoid XQuery processors that use static type checking. (Sorry for the snarky conclusion; I feel I've earned the right. :-) )
NEW ANSWER BASED ON UPDATED INFORMATION: It sounds like static type checking is a red herring (a big fat one). I believe you are in fact not dealing with an element but a document node, which is the invisible root node that contains the top-level element (document element) in the XPath data model representation of a well-formed XML document.
The tree is thus modeled like this:
[document-node]
|
<docElement>
|
<subelement>
and not like this:
<docElement>
|
<subelement>
I had assumed you were passing the <docElement> node. But if I'm right, you were actually passing the document node (its parent). Since the document node is invisible, its serialization (what you copied and pasted) is indistinguishable from an element node, and the distinction was lost when you pasted what is now interpreted as a bare element constructor in your XQuery. (To construct a document node in XQuery, you have to wrap the element constructor with document{ ... }.)
The instance of test fails because the node is not an element but a document-node. (It's not a node() per se, because there's no such thing; see explanation above.)
Also, this would explain why data() returns empty when you tried to get the <subelement> child of the document node (after relaxing the function argument type to node()). The first tree representation above shows that <subelement> is not a child of the document node; thus it returns the empty sequence.
Now for the solution. Before passing the (document node) parameter, get its element child (the document element), by appending /* (or /element() which is equivalent) like this:
let $parameter := someNamespace:functionX()/*
return local:myFunction($parameter)
Alternatively, let your function take a document node and update the argument you pass to data():
declare function local:myFunction($arg1 as document-node()) as element() {
let $value := data($arg1/*/subelement)
etc...
};
Finally, it looks like the description of eXist's request:get-data() function is perfectly consistent with this explanation. It says: "If its not a binary document, we attempt to parse it as XML and return a document-node()." (emphasis added)
Thanks for the adventure. This turned out to be a common XPath gotcha (awareness of document nodes), but I learned a few things from our detour into static type checking.
This works perfectly using Saxon 9.3:
declare namespace my = "my:my";
declare namespace their = "their:their";
declare function my:fun($arg1 as element()) as element()
{
$arg1/a
};
declare function their:fun2($arg1 as node()) as node()
{
$arg1
};
my:fun(their:fun2(/*) )
when the code above is applied on the following XML document:
<t>
<a/>
</t>
the correct result is produced with no error messages:
<a/>
Update:
The following should work even with the most punctuential static type-checking XQuery implementation:
declare namespace my = "my:my";
declare namespace their = "their:their";
declare function my:fun($arg1 as element()) as element()
{
$arg1/a
};
declare function their:fun2($arg1 as node()) as node()
{
$arg1
};
let $vRes := their:fun2(/*)
(: this prevents our code from runtime crash :)
return if($vRes instance of element())
then
(: and this assures the static type-checker
that the type is element() :)
my:fun(their:fun2(/*) treat as element())
else()
node() is an element, attribute, processing instruction, text node, etc.
But data() converts the result to a string, which isn't any of those; it's a primitive type.
You might want to try item(), which should match either.
See 2.5.4.2 Matching an ItemType and an Item in the W3C XQuery spec.
Although it's not shown in your example code, I assume you are actually returning a value (like the $value you are working with) from the local:myFunction.
I have the following code
$pageName = "test";
$Container = {};
I like to set a property of $Container by a variable. I tried $Container.set("test", $pageName);. It didn't raise any errors, but $Container.test or $Container.get("test"); display nothing.
How do I fix it?
The problem is that set is the wrong method. You need to do a put. Remember - Velocity is calling the Java methods. There is no "set" method on a Map object.
Specifically, you can do
$Container.put("test", $pageName)
Now, one weird thing is that this will print "true" or "false" in the page, since the Map.put() method returns a boolean. So I always do
#set($dummy = $Container.put("test", $pageName))
which does the put and stores the result in another reference (which you can then ignore) instead of rendering it to the page.
Hey I ran into the same problem is the "true" or "false" printed on the page, and there is a simpler way to handle it. What I did is a little weird, and I did it Confluence, which of course uses Velocity under the covers. I mention that because I understand Velocity can be used in may different applications.
With a Confluence user macro, I check for a previously created attribute on the req variable, the request variable, i.e. "myPageVars". Then I use the put method to put a new key-value pair, based on the macro parameters. By using the $! prefix, rather than just $, the output isn't sent to the screen.
...
$!req.getAttribute("myPageVars").put( $paramKey, $paramValue )
...
I'm somewhat new to Velocity, so I can't guarantee this will work in every context, but it seems syntactically easier than the whole #set ($dummy etc. line.