Purity of Phobos reduce - function

Why isn't std.algorithm.reduce in Phobos pure? Is it an unfixed Issue or is there a reason why it can't be?
Has this something todo with the question:
"What does a pure function look like"
Andrei asked in the final lecture at DConf 2013?
See: http://forum.dlang.orgthread/20120306224101.GA30389#quickfur.ath.cx
I want the function sparseness in the following code to be pure. I guess I could always replace reduce with a foreach loop for now right?
import std.algorithm: reduce, min, max;
import std.typetuple: templateAnd;
import std.traits: isArray, Unqual;
import std.range: ElementType, isInputRange, isBidirectionalRange, isFloatingPoint;
//** Returns: true if $(D a) is set to the default value of its type. */
bool defaulted(T)(T x) #safe pure nothrow { return x == T.init; }
alias defaulted untouched;
/** Returns: Number of Default-Initialized (Zero) Elements in $(D range). */
size_t sparseness(T)(in T x, int recurseDepth = -1) #trusted /* pure nothrow */ {
import std.traits: isStaticArray;
static if (isStaticArray!T ||
isInputRange!T) {
import std.range: empty;
immutable isEmpty = x.empty;
if (isEmpty || recurseDepth == 0) {
return isEmpty;
} else {
const nextDepth = (recurseDepth == -1 ?
recurseDepth :
recurseDepth - 1);
static if (isStaticArray!T) { // TODO: We can't algorithms be applied to static arrays?
typeof(return) ret;
foreach (ref elt; x) { ret += elt.sparseness(nextDepth); }
return ret;
} else {
import std.algorithm: map, reduce;
return reduce!"a+b"(x.map!(a => a.sparseness(nextDepth)));
}
}
} else static if (isFloatingPoint!T) {
return x == 0; // explicit zero because T.init is nan here
} else {
return x.defaulted;
}
}
unittest {
assert(1.sparseness == 0);
assert(0.sparseness == 1);
assert(0.0.sparseness == 1);
assert(0.1.sparseness == 0);
assert(0.0f.sparseness == 1);
assert(0.1f.sparseness == 0);
assert("".sparseness == 1);
assert(null.sparseness == 1);
immutable ubyte[3] x3 = [1, 2, 3]; assert(x3[].sparseness == 0);
immutable float[3] f3 = [1, 2, 3]; assert(f3[].sparseness == 0);
immutable ubyte[2][2] x22 = [0, 1, 0, 1]; assert(x22[].sparseness == 2);
immutable ubyte[2][2] x22z = [0, 0, 0, 0]; assert(x22z[].sparseness == 4);
}
Update:
I decided on instead using isIterable and foreach instead of the above, as this works just aswell for me right now and makes things #safe pure nothrow. I see no need right now to use higher order functions to solve this problem. I also found Davids Simchas' upcoming std.rational very natural to use here:
import rational: Rational;
/** Returns: Number of Default-Initialized (Zero) Elements in $(D x) at
recursion depth $(D depth).
*/
Rational!ulong sparseness(T)(in T x, int depth = -1) #safe pure nothrow {
alias R = typeof(return); // rational shorthand
static if (isIterable!T) {
import std.range: empty;
immutable isEmpty = x.empty;
if (isEmpty || depth == 0) {
return R(isEmpty, 1);
} else {
immutable nextDepth = (depth == -1 ? depth : depth - 1);
ulong nums, denoms;
foreach (ref elt; x) {
auto sub = elt.sparseness(nextDepth);
nums += sub.numerator;
denoms += sub.denominator;
}
return R(nums, denoms);
}
} else static if (isFloatingPoint!T) {
return R(x == 0, 1); // explicit zero because T.init is nan here
} else {
return R(x.defaulted, 1);
}
}

If you change nextDepth to immutable rather than const then sparseness will be pure.
I believe this is a bug, it may be to do with the closure being passed to reduce capturing nextDepth, and for some reason thinking it may be mutable because it is const. Values declared as const are however identical to those declared as immutable -- the difference only manifests itself with indirections -- so I believe it is an error.
You may want to file a minimal repro case as a bug.
(it cannot be nothrow however, because reduce can, in fact, throw)

Related

Defining the interface for a function using function properties

As you may know, functions in JavaScript can have properties as any object. For example (taken from the excellent JavaScript: The Definitive Guide, 6th ed, p. 178) computes a factorial using the function as memoization array:
function factorial(n: number): number {
if (isFinite(n) && n > 0 && n == Math.round(n)) {
if (!(n in factorial))
factorial[n] = n * factorial(n - 1);
return factorial[n];
}
else
return NaN;
}
factorial[1] = 1;
I tried defining the following interface:
interface Factorial {
(n: number) : number;
[ index: number ]: number;
}
But the compiler is telling me that Type '(n: number) => number' is not assignable to type 'Factorial'. Index signature is missing in type '(n: number) => number'.
I can't do the obvious thing and just define private index: number; inside the function, I'm stumped.
What you have is an example of hybrid types. You have to use type assertion to make sure the function complies with the interface:
let factorial = function (n: number): number {
if (isFinite(n) && n > 0 && n == Math.round(n)) {
if (!(n in factorial))
factorial[n] = n * factorial(n - 1);
return factorial[n];
}
else
return NaN;
} as Factorial;
factorial[1] = 1;

Reuse sortCompareFunction across DataGridColumns in AS3

I put together a DataGrid using the following functions
public function get dataGridColumns():Array {
var dataGridColumnArray:Array = [];
dataGridColumnArray.push(createDataGridColumn(col1, "field1", 0.17, sortStrings));
dataGridColumnArray.push(createDataGridColumn(col2, "field2", 0.17, sortStrings));
dataGridColumnArray.push(createDataGridColumn(col3, "field3", 0.17, sortStrings));
return dataGridColumnArray;
}
private static function createDataGridColumn(columnName:String, dataField:String, width:Number,sortCompareFunction:Function = null):DataGridColumn {
var column:DataGridColumn = new DataGridColumn(columnName);
column.dataField = dataField;
column.width = width;
column.sortCompareFunction = sortCompareFunction;
return column
}
private function sortStrings(a:Object, b:Object, fields:Array = null):int{
if(a.toString().toLowerCase() > b.toString().toLowerCase()){
return 1;
}else if(a.toString().toLowerCase() < b.toString().toLowerCase()){
return -1;
}else{
return 0;
}
}
Since my dataProvider is an array of data objects I run into the problem that a and b in the sort function are objects, and I want to somehow pass the data field (column title) into the sort so I can check the correct object property all using one sort function so it would look something like:
private function sortStrings(a:Object, b:Object, field:String):int{
if(a.field.toLowerCase() > b.field.toString().toLowerCase()){
return 1;
}else if(a.field.toString().toLowerCase() < b.field.toString().toLowerCase()){
return -1;
}else{
return 0;
}
}
I have not figured out a good way to do this yet, and worst case scenario I have 6 extremely similar sort functions.
you can make a comparators factory function, which will return closures, enclosing the field name:
private function createComparatorFor(field:String):Function {
return function (a:Object, b:Object, fields:Array = null):int{
const aField:String = a[field].toString().toLowerCase();
const bField:String = b[field].toString().toLowerCase();
if (aField > bField) {
return 1;
}
if (aField < bField) {
return -1;
}
return 0;
}
}
and use it like this:
dataGridColumnArray.push(createDataGridColumn(
col1, "field1", 0.17, createComparatorFor("field1")));
untested, but should work

Whats wrong with my function?

My char read function isnt working, it prints what i would like it to print but it prevents the program from going to the next step and and reading what number the user inputted, it worked fine before it was a function but i need it to have a certain amount of functions as this is an assignment
#include "aservelibs/aservelib.h"
#include <stdio.h>
#include <math.h>
int length();
float mtof( int note);
float octave(int notes);
char read(char print);
int main()
{
//do while the user hasnt pressed exit key (whatever)
int control[8] = {74, 71, 91, 93, 73, 72, 5, 84};
int index;
int mod;
float frequency;
int notes[8];
int response;
float octave;
char print;
mod = aserveGetControl(1);
//ask backwards, forwards, exit
//SCALING
//(getControl(75) / ((127 - 0) / (1000 - 100))) + 100;
while(true)
{
read(print);
mod = 0;
if(response == 1)
{
while(mod==0)
{
for(index = 0; index < 8; index++)
{
notes[index] = aserveGetControl(control[index]);
frequency = mtof(notes[index]);
aserveOscillator(0, frequency, 1.0, 0);
aserveSleep(length());
printf("Slider Value:%5d\n", notes[index]);
printf("frequency: %f\n", frequency);
mod = aserveGetControl(1);
octave = aserveGetControl(7);
}
}
}
else if(response == 2)
{
while(mod==0)
{
for(index = 7; index > 0; index--)
{
notes[index] = aserveGetControl(control[index]);
frequency = mtof(notes[index]);
aserveOscillator(0, frequency, 1.0, 0);
aserveSleep(length());
printf("Slider Value:%5d\n", notes[index]);
printf("%f", frequency);
mod = aserveGetControl(1);
}
}
}
else if(response == 0)
{
return 0;
}
}
}
int length()
{
return (aserveGetControl(75)/((127.0 - 0) / (1000 - 100))) + 100;
}
float mtof( int note)
{
return 440 * pow(2, (note-69) / 12.0);
}
float octave(int note)
{
float slider = aserveGetControl(7) / 16383.0;
slider *=24;
return 440 * pow(2, ((note+slider)-69) / 12.0);
}
char read(char print)
{
char response;
printf("Run Loop Forwards (1), Backwards (2), Exit (0)\nMove modwheel to return to menu\n");
scanf("%c", &response);
}
You need to return response from read:
char read(char print)
{
char response;
printf("Run Loop Forwards (1), Backwards (2), Exit (0)\nMove modwheel to return to menu\n");
scanf("%c", &response);
return response;
}
and you need to assign it in the main path of your code:
response = read(print);
I'd like to point out that you should really declare response as a char since that is what you are returning from read. Also, I can't see print being used anywhere so I'm not sure of the purpose of passing it to read.

Can I stop Angular.js’s json filter from excluding properties that start with $?

Angular.js has a handy built-in filter, json, which displays JavaScript objects as nicely formatted JSON.
However, it seems to filter out object properties that begin with $ by default:
Template:
<pre>{{ {'name':'value', 'special':'yes', '$reallyspecial':'Er...'} | json }}</pre>
Displayed:
{
"name": "value",
"special": "yes"
}
http://plnkr.co/edit/oem4HJ9utZMYGVbPkT6N?p=preview
Can I make properties beginning with $ be displayed like other properties?
Basically you can't. It is "hard-coded" into the filter's behaviour.
Nonetheless, it is quite easy to build a custom JSON filter that behaves identically with the Angular's one but not filtering out properties starting with '$'.
(Scroll further down for sample code and a short demo.)
If you take a look at the 1.2.15 version source code, you will find out that the json filter is defined like this:
function jsonFilter() {
return function(object) {
return toJson(object, true);
};
}
So, it uses the toJson() function (the second parameter (true) means: format my JSON nicely).
So, our next stop is the toJson() function, that looks like this:
function toJson(obj, pretty) {
if (typeof obj === 'undefined') return undefined;
return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
}
This function makes use of the "native" JSON.stringify() function, passing a custom replacer function (toJsonReplacer).
The toJsonReplacer() function handles some special cases: It checks if the key starts with $ and ignores it if it does (this is what we want to change) and it checks if the value is either a Window, a Document or a Scope object (in which case it converts it to a descriptive string in order to avoid "Converting circular structure to JSON" errors).
function toJsonReplacer(key, value) {
var val = value;
if (typeof key === 'string' && key.charAt(0) === '$') {
val = undefined;
} else if (isWindow(value)) {
val = '$WINDOW';
} else if (value && document === value) {
val = '$DOCUMENT';
} else if (isScope(value)) {
val = '$SCOPE';
}
return val;
}
For the sake of completeness, the two functions that check for Window and Scope look like this:
function isWindow(obj) {
return obj && obj.document && obj.location && obj.alert && obj.setInterval;
}
function isScope(obj) {
return obj && obj.$evalAsync && obj.$watch;
}
Finally, all we need to do is to create a custom filter that uses the exact same code, with the sole difference that our toJsonReplacer() won't filter out properties starting with $.
app.filter('customJson', function () {
function isWindow(obj) {
return obj &&
obj.document &&
obj.location &&
obj.alert &&
obj.setInterval;
}
function isScope(obj) {
return obj &&
obj.$evalAsync &&
obj.$watch;
}
function toJsonReplacer(key, value) {
var val = value;
if (isWindow(value)) {
val = '$WINDOW';
} else if (value && (document === value)) {
val = '$DOCUMENT';
} else if (isScope(value)) {
val = '$SCOPE';
}
return val;
}
function toJson(obj, pretty) {
if (typeof obj === 'undefined') { return undefined; }
return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
}
return function(object) {
return toJson(object, true);
};
});
See, also, this short demo.
* The downside is that your custom JSON filter will not benefit from further improvement/enhancement of Angular's json filter, so you'll have to re-define your's to incorporate changes. Of course, for such a basic and simple filter like this, one should'nt expect frequent or extensive changes, but that doesn't mean there aren't going to be any.

How to test if an object is a vector?

I want to test if an object is a vector, any vector, not only a vector of a single type.
I ran a test:
var v:Vector.<int> = new Vector.<int>();
v.push(3);
v.push(1);
v.push(2);
trace(v is Array); // false
trace(v is Vector); // false
trace(v is Vector.<int>); // true
trace(v is Vector.<*>); // false
It seems that the only thing that returns true is the one which specifies the vector type, but I want to test it for ANY type.
I will need a very efficient method to compare, because getQualifiedClassName is too slow.
My current approach is:
private static function isVector(obj:Object):Boolean {
return (getQualifiedClassName(obj).indexOf('__AS3__.vec::Vector') == 0);
}
But it is 2x slower than the is operator.
I need speed because it's for a object serialization class, and it needs to be very fast.
The problem is that Vector.<*> is a different class than that used for <Number>, <int>, or <uint>. The numeric primitives have special classes for better efficiency. String and Boolean are also primitives, but unlike the numeric primitives they are detected by <*>. As a result, you need only test for the generic Vector and the 3 numeric types.
This solution is over 2 times as fast as getQualifiedClassName in the worst case where the object is either not a Vector, or is a Vector.<uint>, and 5 times faster if the object is a non-primitive base type Vector, like Vector.<Object>:
return (obj is Vector.<*>
|| obj is Vector.<Number>
|| obj is Vector.<int>
|| obj is Vector.<uint>);
Here's a simplistic test:
var moo:Vector.<uint> = new Vector.<uint>();
var timer:Timer = new Timer();
var b:Boolean;
timer.startTimer();
for (var i:int = 0; i < 1000000; i++)
{
b = (moo is Vector.<*>
|| moo is Vector.<Number>
|| moo is Vector.<int>
|| moo is Vector.<uint>);
}
logger.info(" is timer: " + timer.endTimer());
timer.startTimer();
for (i = 0; i < 1000000; i++)
{
b = (flash.utils.getQualifiedClassName(moo).indexOf('__AS3__.vec::Vector') == 0);
}
logger.info("gqcn timer: " + timer.endTimer());
[LOG] com.tcg.test: is timer: 320
[LOG] com.tcg.test: gqcn timer: 756
Change moo to Vector.<Object>:
[LOG] com.tcg.test: is timer: 158
[LOG] com.tcg.test: gqcn timer: 743
Other methods are way too inefficient, so I'm still using my approach:
private static function isVector(obj:Object):Boolean {
return (getQualifiedClassName(obj).indexOf('__AS3__.vec::Vector') == 0);
}
trace(new Array().fixed);//undefined
trace(new Object().fixed);//undefined
trace(new Vector.<Sprite>().fixed);//false
trace(new Vector.<*>().fixed);// false
If you need serialization for any kind of object, you have to iterate over all possible types anyway, so you could use a sequential approach to find your vector type:
v is ... (simple data types)
v is ... (object types that are not collections)
v is Array
v is XMLList
v is ... (all other collection types you can think of)
if none of the above is true, it must be a vector
serialize objects in the vector. If you have more than one type, it's Vector.<*>, otherwise set the vector type according to the object type of the content items.
Use
(obj as Vector.<*>) is Vector.<*>
/// Return Class of any Target
static public function getClass( Target:* ):Class
{
return getDefinitionByName ( getQualifiedClassName( Target ) ) as Class ;
}
/// Check if object is type of Vector.< * >
static public function isVector( any:* ):Boolean
{
return String( getClass( any ) ).indexOf( "[class Vector.<" ) > -1;
}
/// Get Vector < Class >
static public function getVectorType( vector:* ):Class
{
var c:String = String( getClass( vector ) );
var s:int = c.indexOf( '<' ) + 1;
var e:int = c.indexOf( '>' );
return getDefinitionByName( c.substring( s, e ) ) as Class;
}
private function getIsVector(obj:Object):Boolean
{
return String(obj.constructor).indexOf('[class Vector.<*>]') == 0;
}