Coding: Fleeting Thoughts

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

User avatar
Flumble
Yes Man
Posts: 2236
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Fri May 03, 2019 3:39 pm UTC

Make some kind of ziplist iterator that provides immutable references to all previous and next items while providing a mutable reference to the current item. :D

Would it make sense to map over the collection producing a collection of Option<Mesh> objects (Some if a mesh is generated) and then zip the two collections? Or can the (re)generation of one mesh depend on the (re)generation of another mesh during the same iteration?

Tub
Posts: 468
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Fri May 03, 2019 10:00 pm UTC

Flumble wrote:Would it make sense to map over the collection producing a collection of Option<Mesh> objects (Some if a mesh is generated) and then zip the two collections? Or can the (re)generation of one mesh depend on the (re)generation of another mesh during the same iteration?

Yeah, I can push all the changes to a separate collection, then merge the changes back into the original collection as a separate pass. That's what I implemented for now. It's cheap compared to the mesh generation, but it's still pointless overhead just to appease the compiler.

I was promised readable idiomatic code with zero-costs abstractions, and now I need to sacrifice both readability and performance just to make it compile. Not sure how I feel about that.

Next step is to implement the actual Octree in Rust. Let's see how pretty the solution for a recursive data structure ends up. I'm anticipating more pain because each object must be both in a HashMap (based on id) and in the Octree (based on location), and although I can guarantee that to be safe, I'm afraid the compiler won't believe me unless I accept the overhead of ref-counting smart pointers.

Tub
Posts: 468
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Sat May 04, 2019 9:00 pm UTC

Update: I ended up solving the mutability problem by using std::Cell. Cells cheat the whole lifetime issue by disallowing getting a reference to the things inside. You can just copy values in, or copy the current value out. With those semantics, it's safe for them to allow changing the value inside without having a mutable reference to them! Now I can do the whole iteration and regeneration on immutable objects, but still clear the dirty-bit inside a Cell<bool>. Won't solve all of my problems, but for this specific problem the borrow checker is happy.

Octree went well. I needed a bit more boilerplate to specify the type of child pointers (either nullptr, pointing to another node, or pointing to a leaf with objects), but thanks to enums that was a lot less code than other statically typed languages would have required.
For now the octree leaves just store the object ids instead of references to the objects, neatly avoiding all the borrowing issues. That's another HashMap lookup per visible object per frame, but those lookups are cheaper than drawing the object, so I guess it's fine. Still irks me, but it's fine.

The previous javascript implementation used a Heap, added all the visible objects by distance, then continued to draw them front-to-back. In rust, I ended up implementing this as a lazy iterator, allowing me to consume items before the Heap is completely filled. Not sure if that's actually faster, but it was a fun challenge.
The Iterator required a ton of boilerplate for all the types, their trait implementations and everything (the BinaryHeap requires 4 traits on its entries just to specify sort order!), but the iterator was really straightforward. Pop the closest item from the queue; if it's an Octree node add all the children to the queue (frustum culled), if it's an Object return it. Match expressions really shine here.

It's also fast. Counting the time between starting the game and watching the last object pop in, the wasm implementation appears to be ~20-50% faster. Success.

Now for the difficult part: not losing interest in the project after finishing the proof-of-concept. :roll:

User avatar
Flumble
Yes Man
Posts: 2236
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Tue May 07, 2019 12:12 pm UTC

Can I get a smartphone (android/ios) to keep javascript and location services active while the screen is off? I'd like to track my (and friends') running and send it to a server in realtime, preferably from a webpage (stores are expensive and sideloading is hard) and without having the phone in drainage mode.

Most of what I found so far are stackoverflow questions of 5+ years ago.


Tub wrote:Now for the difficult part: not losing interest in the project after finishing the proof-of-concept. :roll:

The goal is the proof-of-concept, right? :mrgreen:

User avatar
Xanthir
My HERO!!!
Posts: 5400
Joined: Tue Feb 20, 2007 12:49 am UTC
Location: The Googleplex
Contact:

Re: Coding: Fleeting Thoughts

Postby Xanthir » Tue May 07, 2019 3:09 pm UTC

Flumble wrote:
Can I get a smartphone (android/ios) to keep javascript and location services active while the screen is off? I'd like to track my (and friends') running and send it to a server in realtime, preferably from a webpage (stores are expensive and sideloading is hard) and without having the phone in drainage mode.

Most of what I found so far are stackoverflow questions of 5+ years ago.

No, you can't. It's a sensitive operation that we're not willing to allow a page to push into a background Service Worker and invisibly track you with; the page needs to be open and active to receive location data.

Native apps are just security/privacy nightmares.
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
Flumble
Yes Man
Posts: 2236
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Tue May 07, 2019 10:28 pm UTC

Xanthir wrote:No, you can't. It's a sensitive operation that we're not willing to allow a page to push into a background Service Worker and invisibly track you with; the page needs to be open and active to receive location data.

You standards people always ruin everything!!1! First you can't just retrieve a precise location without the user's permission, now you can't even track people whenever you like! :roll:

I guess I'll go with "keep your phone unlocked constantly" for now. The reason I want to send the position in real time in the first place, is so you can see each other on the map in real time, for which you'll need the screen turned on anyway. (Telling the relative distance would be neat too, but with that much overengineering I may as well put in the effort of turning it into a native program that can access the location in the background.)

User avatar
Xeio
Friends, Faidites, Countrymen
Posts: 5101
Joined: Wed Jul 25, 2007 11:12 am UTC
Location: C:\Users\Xeio\
Contact:

Re: Coding: Fleeting Thoughts

Postby Xeio » Wed May 08, 2019 3:42 am UTC

I can't decide if this is beautiful or horrifying:

Code: Select all

private static string GetFullName(ClassDeclarationSyntax @class)
{
    string fullName = @class.Identifier.ValueText;
    SyntaxNode node = @class;
    while(true)
    {
        switch (node.Parent)
        {
            case NamespaceDeclarationSyntax @namespace:
                fullName = $"{@namespace.Name}.{fullName}";
                break;
            case ClassDeclarationSyntax outerClass:
                fullName = $"{outerClass.Identifier.ValueText}.{fullName}";
                break;
            default:
                return fullName;
        }
        node = node.Parent;
    }
}

Tub
Posts: 468
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Thu May 09, 2019 3:29 pm UTC

TIL that google will happily store and monetize all of your location data, but considers it a privacy problem when someone else does. :roll:

Xeio wrote:I can't decide if this is beautiful or horrifying:

It can be used for good or evil. I wonder, which is it?

Tub
Posts: 468
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Sat May 18, 2019 10:00 pm UTC

Tub wrote:It's also fast. Counting the time between starting the game and watching the last object pop in, the wasm implementation appears to be ~20-50% faster. Success.

I wasn't happy with this. A bit of benchmarking later, the mesh generation code has been improved by another +120% on top of the previous improvements.

I wouldn't know how to do these kinds of optimizations in a high level language (like JS) when targeting an unknown and changing environment (like a browser).

So my thoughts of the day are:
  • If you need speed, and you're willing to invest the time, wasm works.
  • Hash maps are at the core of most dynamic languages, used to implement objects. Lookups are O(1) and presumed to be really fast. However, when you're doing ~150.000 of them per frame, it helps to bring that number down, and it also helps to use a faster (but less secure) hashing function than the default one.

User avatar
Flumble
Yes Man
Posts: 2236
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Mon May 27, 2019 4:48 pm UTC

Code: Select all

const /*or let or var*/ variable = someFunctionOf(variable)

The javascript complaineth. I am sad. Though recursive binding is allowed for the "old" function syntax:

Code: Select all

function variable() {
  return someFunctionOf(variable)
}

Sure, let v=v+5 would make a mess, but in my case someFunctionOf behaves perfectly fine (e.g. (_)=>0) ...if javascript would create a(n undefined) reference for variable first and afterwards replace it with the result of the expression. Changing a reference externally is not weird un-javascript behaviour at all. :roll:

So when can we expect a letrec keyword in ecmascript?

User avatar
hotaru
Posts: 1045
Joined: Fri Apr 13, 2007 6:54 pm UTC

Re: Coding: Fleeting Thoughts

Postby hotaru » Tue May 28, 2019 12:31 am UTC

Flumble wrote:Though recursive binding is allowed for the "old" function syntax:

Code: Select all

function variable() {
  return someFunctionOf(variable)
}


the equivalent of that code with const does work, though:

Code: Select all

const variable = () => someFunctionOf(variable);

Code: Select all

factorial product enumFromTo 1
isPrime n 
factorial (1) `mod== 1

User avatar
phlip
Restorer of Worlds
Posts: 7569
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Tue May 28, 2019 6:04 am UTC

it can be interesting to see which dynamic languages let you do this, and which ones don't...

Code: Select all

phlip@boris:~$ python
Python 3.6.7 (default, Oct 22 2018, 11:32:17)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = str(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

phlip@boris:~$ irb
irb(main):001:0> a = a.to_s
=> ""

phlip@charlemagne:~$ js
> var a = '' + a;
> a
'undefined'
> let b = '' + b;
ReferenceError: b is not defined
> const c = '' + c;
ReferenceError: c is not defined

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

Tub
Posts: 468
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Tue May 28, 2019 9:07 am UTC

Flumble wrote:

Code: Select all

const /*or let or var*/ variable = someFunctionOf(variable)

This works does not explode with var. Anything declared with var has a scope of the whole function, being initialized to undefined before its first assignment. It doesn't work with const or let because of their restricted scope and temporal dead zones.

Flumble wrote:

Code: Select all

function variable() {
  return someFunctionOf(variable)
}

function declarations also have function-level scope; you can reference them before, after, and even during declaration.

However, temporal dead zones still apply for captured variables:

Code: Select all

  let foo2 = foo; // referencing works fine
  foo(); // calling it would access x early; this throws.
  let x = 42;
  function foo() {
    return x;
  }
  foo(); // now it works


Flumble wrote:So when can we expect a letrec keyword in ecmascript?

Step #1 would be to show some kind of problem that's easier to solve with the keyword than without. Considering that it works with var, I doubt you'll find one.

Otherwise, Babel is a pretty sweet project. Adding a plugin to implement your favourite code transformation isn't hard.

phlip wrote:it can be interesting to see which dynamic languages let you do this, and which ones don't...

Code: Select all

 ~> php -r '$a = gettype($a); echo $a;'
PHP Notice:  Undefined variable: a in Command line code on line 1
NULL

Depending on your settings (and PHP version), it may output a notice, but otherwise continues as if the variable was NULL.
Last edited by Tub on Tue May 28, 2019 9:14 am UTC, edited 1 time in total.

User avatar
chridd
Has a vermicelli title
Posts: 840
Joined: Tue Aug 19, 2008 10:07 am UTC
Location: ...Earth, I guess?
Contact:

Re: Coding: Fleeting Thoughts

Postby chridd » Tue May 28, 2019 9:11 am UTC

perl:

Code: Select all

$ perl -e 'my $x = $x.""; print $x;'
(no output)
...but...

Code: Select all

$ perl -e 'use strict; my $x = $x.""; print $x'
Global symbol "$x" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
...so at least Perl treats $x in that statement as referring to a global variable in an outer scope.

Also, on my browser, your JavaScript examples give "ReferenceError: can't access lexical declaration `b' before initialization". And

Code: Select all

const d = function() {return d;};
works.

Also, function statements execute before any other statements, so you can call a function before it's defined.
~ chri d. d. /tʃɹɪ.di.di/ (Phonotactics, schmphonotactics) · she · Forum game scores
mittfh wrote:I wish this post was very quotable...

Tub
Posts: 468
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Wed May 29, 2019 10:45 am UTC

I just realized that javascript's Function class has a unique property. All constructors are functions, so they inherit from Function. This includes the Function constructor:

>> Function instanceof Function
true

A small challenge is thus: create a new variable A (with A !== Function) such that
>> A instanceof A === true

This is also possible in PHP, but requires a different approach. I don't know about python or perl. Not sure if Java or C# and their Reflection APIs allow something to be both a variable and a type.

User avatar
Flumble
Yes Man
Posts: 2236
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Wed May 29, 2019 4:35 pm UTC

hotaru wrote:the equivalent of that code with const does work, though:

Oof, that was a blunder. :oops: Yes, very true. (And in both these cases getting something out of variable would require evaluating the function again and again, which would defeat my usecase) Perhaps I've seen too much haskell in the past weeks, forgetting what eager evaluation looks like.

phlip wrote:it can be interesting to see which [...] languages let you do this, and which ones don't...

I'd recommend using an object/list/dictionary to give the language a bit of leeway. Who knows, maybe there's a language that implicitly stores a reference:

Code: Select all

$ python3 -c "a = {'key': a}"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
NameError: name 'a' is not defined

$ echo 'a={"key" => a}' | irb2.5
Switch to inspect mode.
a={"key" => a}
{"key"=>nil}

$ js -p 'var a = {"key": a}; a'
{ key: undefined }

$ perl5.26.1 -e 'use Data::Dumper; my %a=("key"=>%a); print Dumper \%a'
$VAR1 = {
          'key' => undef
        };

$ javac Main.java
Main.java:4: error: self-reference in initializer
   static final Map<String,Object> map = Map.of("key",(Object)map);
                                                              ^

//this is cheating, really
$ printf '#include<iostream>\n#include<map>\n typedef const std::map<std::string,const void*> Map; int main() { Map map = {{"key", &map}}; std::cout << ((Map*)map.at("key"))->begin()->first << std::endl; return 0; }' | g++ -Wall -Wextra -x c++ -
//no errors

$ php7 -r '$a = array("key"=>$a); echo gettype($a["key"])."\n";'
NULL
//could also cheat with '$a = array("key"=>a); echo gettype(${$a["key"]});'

$ ghc -e 'let a = "value":a in print a'
["value","value","value","value","value","value","value","value","value","value","value","valu^C

(By the way, java doesn't even allow a = () -> a.)
Lisp and friends do have recursive bindings (it's what letrec was born to do), but I guess no language on the imperative side can do it.

Tub wrote:A small challenge is thus: create a new variable A (with A !== Function) such that
>> A instanceof A === true

Is it going to involve defineProperty hacks?
Spoiler:
Oh, I missed one trivial case A=Object

Tub
Posts: 468
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Wed May 29, 2019 7:29 pm UTC

Oh. I missed that rather trivial solution, too. It's true, this will also work for all of Function's parents, which is just the one you mentioned.

But no, it can be solved without reusing an existing constructor. I don't think defineProperty will help much.

DavidSh
Posts: 207
Joined: Thu Feb 25, 2016 6:09 pm UTC

Re: Coding: Fleeting Thoughts

Postby DavidSh » Wed May 29, 2019 8:41 pm UTC

In python, both isinstance(type,type) and isinstance(object,object) evaluate to True. You can also set isinstance() for an object to do pretty much anything you want.

Code: Select all

class x(object):
  def __instancecheck__(self,y):
      return True
     
xx = x()

isinstance(xx,xx)
isinstance(3,xx)

Anything is an instance of xx generated in this way.

User avatar
phlip
Restorer of Worlds
Posts: 7569
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Thu May 30, 2019 12:33 am UTC

Python2 old-style classes are also just total jank and you can do whatever the hell you want:

Code: Select all

>>> class A:
...   pass
...
>>> A.__class__ = A
>>> isinstance(A, A)
True

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

Tub
Posts: 468
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Tue Jun 04, 2019 9:50 am UTC

Going to resolve this real quick.

Quoting mdn on instanceof:
The instanceof operator tests whether the prototype property of a constructor appears anywhere in the prototype chain of an object.

For A instanceof A, you need A to
* be a constructor (a function) and an instance
* as a constructor, have a prototype (aka parent class), which is A.__proto__ (nonstandard) or Object.getPrototypeOf(A) (modern)
* as an instance, have that prototype inside of its prototype chain (A.prototype, or further up the chain)

Doing those requirements verbatim, you can do this:

Code: Select all

function A() {}
A.prototype = Object.getPrototypeOf(A);

But then A is just a plain function, not a custom class. If you want your own prototype in there, you'll find that you cannot simultaneously define A as function A() and as A = Object.create(..). But there's Object.setPrototypeOf:

Code: Select all

function A() { };

let proto = { };
Object.setPrototypeOf(A, proto);

A.prototype = Object.getPrototypeOf(A);


In PHP, the trick is a bit different. The operator is defined as [instance] instanceof [class], usually $A instanceof Foo.
[instance] can be a variable $A or a constant A.
[class] can be a class name, or a string variable holding a class name.

Code: Select all

A instanceof A

This might work if A is both a constant and a class name (not sure how PHP resolves the naming conflicts), but constants cannot hold objects, just primitive types. Primitive types are never an instance of any class.

Code: Select all

$A instanceof $A

This works if $A is an object of our class, and a string holding the name of our class. Remembering that strings are primitive types, not objects, can this be done? Thanks to type coercion, it can.

Code: Select all

class Foo {
   public function __toString() {
      return 'Foo';
   }
};

$A = new Foo();

echo ($A instanceof $A) ? 'yes' : 'no';


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 6 guests