Coding: Fleeting Thoughts

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

Moderators: phlip, Moderators General, Prelates

User avatar
headprogrammingczar
Posts: 3072
Joined: Mon Oct 22, 2007 5:28 pm UTC
Location: Beaming you up

Re: Coding: Fleeting Thoughts

Postby headprogrammingczar » Sun Aug 09, 2015 11:05 pm UTC

By the way, when you want to do anything interesting, you aren't dealing with Reader, Writer, or State directly, but some other thing that implements their mtl class equivalent. Ironically, that ends up being easier to understand, because instead of "here's this simple concept, depicted here in 10 really dense functions", you get "here's this type that represents something really complicated, but who cares about how it works because this is the API".

Also for what it's worth, the definitions you have found I bet are deliberately confusing. The definition on hackage is asks f = ReaderT (return . f), which bears out your noticing that asks = Reader (in the specific case of Reader).

To clear up the confusion on (->), it's a built-in type constructor, just like Int, (), IO, etc. Its only secret sauce is that values of that type are constructed with lambda and it doesn't follow the usual "uppercase operator" rule for constructors. Beyond that, (->) is as good as cash.
<quintopia> You're not crazy. you're the goddamn headprogrammingspock!
<Weeks> You're the goddamn headprogrammingspock!
<Cheese> I love you

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

Re: Coding: Fleeting Thoughts

Postby Xanthir » Sun Aug 09, 2015 11:46 pm UTC

The place I was reading from was https://wiki.haskell.org/All_About_Monads :/
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

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

Re: Coding: Fleeting Thoughts

Postby phlip » Thu Aug 13, 2015 2:21 pm UTC

So, apparently my sister found a compiler bug, which is always fun. I don't speak Ada in the slightest, but I'm sure someone here will find it interesting...

Code: Select all

with Ada.Text_IO; use Ada.Text_IO;

procedure Ordering_Test is
  type Mod_Type is mod 5;
begin
  for I in Mod_Type loop
    Put_Line (Mod_Type'Image (I) & " <" & Mod_Type'Image (I + 1) & " ? " &
      Boolean'Image (I < I + 1));
  end loop;
  Put_Line (Mod_Type'Image (Mod_Type'Last) & " <" & Mod_Type'Image (Mod_Type'First) & " ? " &
    Boolean'Image (Mod_Type'Last < Mod_Type'First));
end Ordering_Test;

Code: Select all

0 < 1 ? TRUE
1 < 2 ? TRUE
2 < 3 ? TRUE
3 < 4 ? TRUE
4 < 0 ? TRUE
4 < 0 ? FALSE


Apparently, when you insist, in the face of all reasonableness, that the set of integers mod-n should be ordered, the compiler makes some incorrect optimisations...

Code: Select all

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

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

Re: Coding: Fleeting Thoughts

Postby Flumble » Fri Aug 14, 2015 12:11 am UTC

Which comparison is done on I < I+1? Are I and I+1 compared as Mod_Types, namely Mod_Type'Last vs Mod_Type'First? Or are they implicitely converted to integer numbers (most likely because of the +1) and compared as such?
I don't know how Ada does operator overloading and whatnot, but I suspect this might be the case.

Anyway, it shouldn't be returning booleans at all, but unknowns or errors. (OTOH I vaguely remember a discussion about ordering being independent of successor functions)

korona
Posts: 495
Joined: Sun Jul 04, 2010 8:40 pm UTC

Re: Coding: Fleeting Thoughts

Postby korona » Fri Aug 14, 2015 10:17 pm UTC

While it is relatively easy to get a "confused by earlier errors, bailing out" message from GCC I never encountered a GCC segfault until yesterday (while compiling c++1y automatic return type deduction code with gcc 4.8). Restructuring the code fixed it although I still think my code was actually correct.

User avatar
jestingrabbit
Factoids are just Datas that haven't grown up yet
Posts: 5967
Joined: Tue Nov 28, 2006 9:50 pm UTC
Location: Sydney

Re: Coding: Fleeting Thoughts

Postby jestingrabbit » Sat Aug 15, 2015 10:30 am UTC

phlip wrote:Apparently, when you insist, in the face of all reasonableness, that the set of integers mod-n should be ordered, the compiler makes some incorrect optimisations...


You know, I kinda like what it did. Its wrong, but there's a rightness to it.
ameretrifle wrote:Magic space feudalism is therefore a viable idea.

User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: Coding: Fleeting Thoughts

Postby The Great Hippo » Sun Aug 16, 2015 12:41 am UTC

I feel like I'm going about this task in a really inefficient, backward way. The goal is to take two dictionaries {A and B} and produce a new dictionary {C}.

Dictionary A maps things to their definitions; Dictionary B maps things to sets of things defined in Dictionary A. Basically, A defines a thing, and B groups a thing -- with the added detail that a thing can belong to multiple groups, and you can also have groups of groups (so long as every group has defined members). Dictionary C is a flat dictionary-of-dictionaries (the inner dictionary maps to sets); it just has groups as its keys, and mappings of things to their definitions as its values.

Spoiler:

Code: Select all

taxonomy = {
    "MouseInputs" :     {
            "MouseMotion",
            "MouseButton",
                        },

    "Inputs" :          {
            "MouseInputs",
            "KeyDown"
                        },

    "MouseButton" :     {
            "MouseButtonDown",
            "MouseButtonUp"
                        }
            }


definitions =   {
    "MouseMotion" : {"rel", "buttons"},
    "MouseButtonDown" : {"button", "pos"},
    "MouseButtonUp" : {"button", "pos"},
    "KeyDown" : {"key"}
                }
               

class Taxonomy:
   
    def __init__(self, members, taxonomy):
        self.members = members
        self.groups = dict()
        self.data = dict()
        self.process_data(taxonomy)

    def process_data(self, taxonomy):
        defined_groups = dict()
        undefined_groups = set()
        for key in taxonomy:
            if key not in self.members:
                # this is a defined group
                defined_groups[key] = taxonomy[key]
                undefined_groups.discard(key)
                for member in taxonomy[key]:
                    if (member not in self.members and
                            member not in defined_groups):
                        undefined_groups.add(member)
        if undefined_groups:
            raise TypeError("Undefined groups!")
        self.groups.update(defined_groups)
        self.assign_members()

    def assign_members(self):
        for group in self.groups:
            for member in set(self.groups[group]):
                if member in self.groups:
                    self.groups[group].discard(member)
                    self.groups[group].update(self.groups[member])
        for group in self.groups:
            new_dict = dict()
            for member in self.groups[group]:
                new_dict[member] = self.members[member]               
            self.groups[group] = new_dict
           
               

tax = Taxonomy(definitions, taxonomy)
print (tax.groups)


I feel like I'm trying to reinvent the wheel; the problem I'm trying to solve seems really common, so I can't imagine there isn't a much more elegant pre-existing solution.

EDIT: Pardon the very messy code; it's a first-draft attempt to solve the problem.

EDIT-EDIT: Also, the above code is broken, and doesn't even work (it only worked when I ran it before because I'm using an online Python parser and keep forgetting to reset it after every test -- so I keep forgetting that objects are still floating around from my previous run >.>)

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

Re: Coding: Fleeting Thoughts

Postby Xanthir » Sun Aug 16, 2015 3:43 am UTC

I can't quite tell from your description what your desired output is. Can you give an example?
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: Coding: Fleeting Thoughts

Postby The Great Hippo » Sun Aug 16, 2015 4:09 am UTC

Sure!
Spoiler:
Input:

Code: Select all


dictionary_a = {
        "MouseInputs" :       {"MouseMotion", "MouseButton"},
        "Inputs" :          {"MouseInputs", "KeyDown"},
        "MouseButton" :       {"MouseButtonDown", "MouseButtonUp"}
               }


dictionary_b=  {
        "MouseMotion" :     {"rel", "buttons"},
        "MouseButtonDown" : {"button", "pos"},
        "MouseButtonUp" :   {"button", "pos"},
        "KeyDown" :         {"key"}
               }
                   


Output:

Code: Select all


dictionary_c = {
        "MouseInputs":
                       {
                        "MouseMotion" :         {"rel", "buttons"},
                        "MouseButtonDown" :     {"button", "pos"},
                        "MouseButtonUp":        {"button", "pos"}
                       },
   "Inputs":     
                       {
                        "MouseMotion" :           {"rel", "buttons"},
                        "MouseButtonDown":      {"button", "pos"},
                        "MouseButtonUp":        {"button", "pos"},
                        "KeyDown":              {"key"}
                       },
   "MouseButton":
                       {
                        "MouseButtonDown":      {"button", "pos"},
                        "MouseButtonUp":        {"button", "pos"}
                       }
                }
         

User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: Coding: Fleeting Thoughts

Postby The Great Hippo » Sun Aug 16, 2015 7:26 am UTC

I managed to write code that takes those two inputs and produces the desired output, but it's much more complex than I'd like it to be -- also, there's a serious recursion-loop risk (though I think I know how to prevent it).

Spoiler:

Code: Select all

grouping = {
        "MouseInputs" :     {"MouseMotion", "MouseButton"},
        "Inputs" :          {"MouseInputs", "KeyDown"},
        "MouseButton" :     {"MouseButtonDown", "MouseButtonUp"}
                }


terms =  {
        "MouseMotion" :     {"rel", "buttons"},
        "MouseButtonDown" : {"button", "pos"},
        "MouseButtonUp" :   {"button", "pos"},
        "KeyDown" :         {"key"}
                }


desired_result = {
        "MouseInputs":
                    {
                        "MouseMotion" :         {"rel", "buttons"},
                        "MouseButtonDown" :     {"button", "pos"},
                        "MouseButtonUp":        {"button", "pos"}
                    },
        "Inputs":
                    {
                        "MouseMotion" :         {"rel", "buttons"},
                        "MouseButtonDown":      {"button", "pos"},
                        "MouseButtonUp":        {"button", "pos"},
                        "KeyDown":              {"key"}
                    },
        "MouseButton":
                    {
                        "MouseButtonDown":      {"button", "pos"},
                        "MouseButtonUp":        {"button", "pos"}
                    }
                }


class Groups:
   
    def __init__(self, grouping, terms):
        self.grouping = grouping
        self.terms = terms
        self.data = dict()
        for group in self.grouping:
            if all(member in self.terms for member in self.grouping[group]):
                self.data[group] = {k:v for k, v in self.terms.items() if k in
                                    self.grouping[group]}
        self.create_groups()
   
    def create_groups(self):
        for group in self.grouping:
            if group in self.data:
                continue
            if all(member in self.terms or member in self.data for member in
                    self.grouping[group]):
                u = {member for member in self.data if member in
                        self.grouping[group]}
                group_terms = dict()
                for member in u:
                    group_terms.update({k:v for k, v in terms.items() if k in
                                        self.data[member]})
                v = {k:v for k, v in self.terms.items() if k in
                        self.grouping[group]}
                v.update(group_terms)
                self.data[group] = v
        if set(self.grouping) != set(self.data):
            self.create_groups()


g = Groups(grouping, terms)

print(g.data)
print(g.data == desired_result)
The last line prints 'True'.

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

Re: Coding: Fleeting Thoughts

Postby Flumble » Sun Aug 16, 2015 11:39 am UTC

Ah, so you have a dictionary in which every key maps to a set of references to either an entry in "the constant* table" or another key. Parsers are great at this, but I guess integrating a whole parser is a bit too much.

One way to go about this, is a breath-first approach: put all unfinished keys (as in: the keys for which one of the value entries is not a constant) in a list (queue) and the finished keys in a seperate list, then loop over the unfinished queue until it's empty. For every element in the queue, replace its value entries with constants* if possible; then put it either in the finished list or back in the unfinished queue.
You can tell it's infinitely recursing when there's no replacing going on for n consecutive items, where n is the size of the queue.

*constants as in: they don't contain references to anything outside.

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

Re: Coding: Fleeting Thoughts

Postby Xanthir » Sun Aug 16, 2015 1:45 pm UTC

The Great Hippo wrote:I managed to write code that takes those two inputs and produces the desired output, but it's much more complex than I'd like it to be -- also, there's a serious recursion-loop risk (though I think I know how to prevent it).


Here's a *much* simpler version:

Code: Select all

def lookup(key, groups, terms):
    if key in terms:
        return {key: terms[key]}
    ret = {}
    for subkey in groups[key]:
        ret.update(lookup(subkey))
    return ret

result = {}
for topLevelKey in grouping:
    result[topLevelKey] = lookup(topLevelKey, grouping, terms)


Here's an version with improved efficiency and infinite-loop prevention:

Code: Select all

def lookup(key, groups, terms, seen=None):
    if key in lookup.memo:
        return lookup.memo[key]
    if seen is None:
        seen = set(key)
    elif key in seen:
        raise "Whoopsiedoodle, loop detected for key '{0}'!".format(key)
    else:
        seen.add(key)
    if key in terms:
        return {key: list(terms[key])}
    ret = {}
    for subkey in groups[key]:
        ret.update(lookup(subkey, groups, terms, seen))
    lookup.memo[key] = ret
    return ret
lookup.memo = {}

result = {}
for topLevelKey in grouping:
    result[topLevelKey] = lookup(topLevelKey, grouping, terms)
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
ucim
Posts: 6888
Joined: Fri Sep 28, 2012 3:23 pm UTC
Location: The One True Thread

Where to put functions

Postby ucim » Sun Aug 16, 2015 3:26 pm UTC

So I'm writing code for a web page, and need to do something simple (like see if something has expired). It's fairly simple:

Code: Select all

if ((isset($expirationdate) && $today>$expirationdate) || (isset($purchasedate) && $today>$purchasedate+DEFAULTSHELFLIFE))
{ do_stuff;
}
I may need a similar condition elsewhere.

1: Does it make sense to create a function (always use functions if you might reuse code)?

Code: Select all

function expired($today, $expirationdate=NULL, $purchasedate=NULL)
{ return ((isset($expirationdate) && $today>$expirationdate) || (isset($purchasedate) && $today>$purchasedate+DEFAULTSHELFLIFE))
}
so that I can then say:

Code: Select all

$expired = expired($today, $expirationdate, $purchasedate);
if ($expired)
{ do_stuff;
}

It doesn't really seem to simply the code much (except that I can change the expiration condition globally).

2: Given the answer is 'yes', where should the function go?
a: in the page?
b: in the big include file that has all functions (so it's available to all pages)
c: somewhere else?

Jose
Order of the Sillies, Honoris Causam - bestowed by charlie_grumbles on NP 859 * OTTscar winner: Wordsmith - bestowed by yappobiscuts and the OTT on NP 1832 * Ecclesiastical Calendar of the Order of the Holy Contradiction * Heartfelt thanks from addams and from me - you really made a difference.

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

Re: Coding: Fleeting Thoughts

Postby Flumble » Sun Aug 16, 2015 8:55 pm UTC

A. Does it make sense to put these conditionals in the php code instead of the database query (or even scheme rules)?
B. Yes, it makes sense to make a function that tests all expiration conditions, even if it's only occurring once. It's even better when it's a pure function (to really comply, you should make shelflife an argument too), so you can tell from the signature alone what is used for determining if something is expired.
C. It doesn't look simplified because you store the result of expired() in a temporary variable (with the same name!) instead of placing expired() inside the if-condition. Besides, the order of the arguments could be a bit confusing –try is_expired($purchase_date, $current_date, $expiration_date, $shelf_life) for example.

User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: Coding: Fleeting Thoughts

Postby The Great Hippo » Sun Aug 16, 2015 9:56 pm UTC

Flumble wrote:Ah, so you have a dictionary in which every key maps to a set of references to either an entry in "the constant* table" or another key. Parsers are great at this, but I guess integrating a whole parser is a bit too much.

One way to go about this, is a breath-first approach: put all unfinished keys (as in: the keys for which one of the value entries is not a constant) in a list (queue) and the finished keys in a seperate list, then loop over the unfinished queue until it's empty. For every element in the queue, replace its value entries with constants* if possible; then put it either in the finished list or back in the unfinished queue.
You can tell it's infinitely recursing when there's no replacing going on for n consecutive items, where n is the size of the queue.

*constants as in: they don't contain references to anything outside.
Just out of curiosity: Is 'table' just another word for 'mapping'? Also, thanks -- this explanation helped me wrap my head around what I was doing wrong.

Xanthir: Oh, wow -- thank you; I appreciate it! I particularly appreciate the more simplified version, because that helps me wrap my head around what's going on (before I actually implement the more efficient, infinite-loop preventative version).

EDIT: As a follow-up question -- I realize this might not be the best place to ask this, but I was wondering -- is it considered 'bad practice' to have a callable object return something radically different based on whether or not you pass an argument or keyword assignments to it?

Class X instances return True or False if you pass a single argument to them; they return Class Y instances if you pass keyword assignments to them (with no positional arguments) -- Class Y is an 'enhanced' version of Class X (it also returns True or False if you pass a single argument to them). The point is so I can have my cake and eat it too -- I can use Class X instances as-is, or I can use them as partial functions / factories for Class Y instances (which use some of the information you instance Class X instances with -- so Class X instances can be seen as incomplete instantiations of Class Y instances).

Nyktos
Posts: 138
Joined: Mon Mar 02, 2009 4:02 pm UTC

Re: Coding: Fleeting Thoughts

Postby Nyktos » Sun Aug 16, 2015 11:33 pm UTC

I would consider that ugly. Sometimes a function returning different types based on the input is reasonable but that usually takes the shape "output type is the same as input type" or something along those lines.

In your case I think it would be better to just give class X a different method that returns class Y instances, rather than using keyword arguments to decide. Explicit is better than implicit, and all that.

User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: Coding: Fleeting Thoughts

Postby The Great Hippo » Mon Aug 17, 2015 12:03 am UTC

Oh; that might work much better!

CheckX objects check if an object is/has X; CheckY objects check if an object is/has Y. CheckAll objects combine any number of CheckX and CheckY objects, checking an object against them all.

My current scheme was to have CheckX objects allow you to get a CheckAll object (with the CheckX object and a new CheckY object) from its check method by passing different parameters. But instead, I can have all my Check classes allow for "and_check_x()" or "and_check_y()" methods, which would return a new CheckAll object with appropriate checkers. My Check objects could all be much more versatile AND explicit. Thanks!

(I think the reason I didn't think to do this in the first place is that recently I've been trying to focus on objects that only have *one* method; the __call__ method. That way, I'm always building simple input/output objects and creating complex networks out of simple things rather than simple networks out of complex things. That being said, this seems like a clear case where multiple methods are a *good* idea!)

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

Re: Coding: Fleeting Thoughts

Postby Flumble » Mon Aug 17, 2015 12:24 am UTC

The Great Hippo wrote:Just out of curiosity: Is 'table' just another word for 'mapping'?

I (mis)used the word table here to discern between mappings to constants and mappings to variable data. Libraries sometimes talk about tables of constants, where the constants are elements in a specific (and sometimes hardwired) array (for which the offset is another named constant :P ).

I'm in favour of using dictionary and dictionary only as the name for key-value pairs.
"table" refers to 2D arrays in general, often with named columns, but not necessarily two and the cells are ordered.
"map" can be confusing, especially when you have a math background, and ambiguous since only a handful of people agree that maps can be functions over any domain instead of manually defined pairs of keys and values.
"dictionary" does have the troubles that it implies ordering (real dictionaries go form A to Z) and duplicate keys (a lot of real dictionaries have repeating lemmas for different meanings of the word). And it's a long word and you can't verbify it easily.

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

Re: Coding: Fleeting Thoughts

Postby phlip » Mon Aug 17, 2015 12:36 am UTC

I find it amusing how different languages refer to the same construct with wildly different names...

C++ and Java refer to it as a "map" (or "hashmap" specifically for the hash-buckets-based implementation). Python calls it a "dict". Perl calls it a "hash", which is... odd (it's like rhyming slang in that it's short for "hashmap" but abbreviates off the bit that's actually important). PHP has "associative arrays" because of course it does. JavaScript's item-lookup and field-lookup concepts are folded together, so its map equivalent is just Object (which is then inherited by JSON). .NET gets a twofer with "IDictionary" implemented by "Hashtable".

Code: Select all

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

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6598
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Mon Aug 17, 2015 12:53 am UTC

.Net 2.0+ also has a Dictionary<TKey, TValue> class (Hashtable pre-dates generics and should probably be deprecated, along with everything else in System.Collections).
Summum ius, summa iniuria.

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

Re: Coding: Fleeting Thoughts

Postby phlip » Mon Aug 17, 2015 1:13 am UTC

(I don't actually .NET, I just got that one from Google. Figures it'd only find me something that was obsolete nearly a decade ago.)

Code: Select all

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

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: Coding: Fleeting Thoughts

Postby ahammel » Mon Aug 17, 2015 1:24 am UTC

phlip wrote:JavaScript's item-lookup and field-lookup concepts are folded together, so its map equivalent is just Object (which is then inherited by JSON).

ES6 has a propper Map class for such things, I'm told. It provides such niceties as nonequivalence between string and integer keys (obj[1] is the same thing as obj['1'], apparently).
He/Him/His/Alex
God damn these electric sex pants!

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

Re: Coding: Fleeting Thoughts

Postby phlip » Mon Aug 17, 2015 1:31 am UTC

ahammel wrote:(obj[1] is the same thing as obj['1'], apparently).

I mean, it wouldn't surprise me... this is JavaScript after all.

Code: Select all

>>> a = {'toString': function() { return "3"; }};
>>> a * 2
6

Code: Select all

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

User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: Coding: Fleeting Thoughts

Postby The Great Hippo » Mon Aug 17, 2015 1:49 am UTC

That's terrible!

Obviously, it should automatically convert 1 to "one" in order to avoid any confusion.

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

Re: Coding: Fleeting Thoughts

Postby Xanthir » Mon Aug 17, 2015 3:18 am UTC

Yes, ES6 has maps and sets. They're already in several browsers. They're more powerful than in many languages, because they allow any object as map keys or set values, not just "hashable" objects. (And they handle NaN correctly - it works as a key. The *only* values which are observably different but treated identically by Map are +0 and -0, because of the high possibility of inadvertent errors that distinguishing them would cause.)

ahammel wrote:(obj[1] is the same thing as obj['1'], apparently)

Objects only have properties, which have string names. obj.foo and obj['foo'] are different syntaxes for the exact same thing - property access. And JS has auto-conversion rules when dealing with primitives, to make things easier. That's why those are the same thing - 1 gets auto-converted to the string "1" for you. Arrays are just normal objects, with string keys, which happen to have the special power to monitor when you set/delete a property with a numeric key so they can adjust their "length" property automatically. (In practice, of course, arrays get optimized to vectors as you'd expect, tho you can de-opt them if you try. Try setting just 0 and 2³²+1, iirc.)

phlip wrote:
ahammel wrote:(obj[1] is the same thing as obj['1'], apparently).

I mean, it wouldn't surprise me... this is JavaScript after all.

Code: Select all

>>> a = {'toString': function() { return "3"; }};
>>> a * 2
6

What's surprising about that? Are you expecting it to just fail entirely? JS's auto-conversion rules will first try to make it a number (calling the .valueOf() method if it exists), and failing that will try to stringify it (calling .toString() if it exists) and then convert that to a number, and only if that fails will it emit a NaN.
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6598
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Mon Aug 17, 2015 3:30 am UTC

I don't think it's surprising that it works, just horrible that it works. Like eww.
Summum ius, summa iniuria.

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: Coding: Fleeting Thoughts

Postby ahammel » Mon Aug 17, 2015 3:34 am UTC

Xanthir wrote:And JS has auto-conversion rules when dealing with primitives, to make things easier.
Well, quite. I'm just not sure that it actually does make things easier, rather than crazy complicated in edge cases.

What's surprising about that? Are you expecting it to just fail entirely?
Yes, that is exactly what I would expect to happen when trying to multiply something that is clearly not a number by three.

JS's auto-conversion rules will first try to make it a number (calling the .valueOf() method if it exists), and failing that will try to stringify it (calling .toString() if it exists) and then convert that to a number, and only if that fails will it emit a NaN.
It's a religious war, I guess, but attempting to do arithmetic with anything that looks like a number when stringified seems like a great source of infuriating bugs.

And after all that, it still doesn't throw an exception? Yeesh.
He/Him/His/Alex
God damn these electric sex pants!

User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: Coding: Fleeting Thoughts

Postby The Great Hippo » Mon Aug 17, 2015 5:13 am UTC

Better still:

Code: Select all

>>> x = "2"
>>> x * 4
>>> x
"eight"

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

Re: Coding: Fleeting Thoughts

Postby Flumble » Mon Aug 17, 2015 9:19 am UTC

The Great Hippo wrote:Better still:

Code: Select all

>>> x = "2"
>>> x * 4
>>> x
"eight"

That's so horrible it can only work for languages that support operator overloading and joke languages. (I mean, that's clearly a subclass of string in C++, for which the multiplication operator sets the string's value to "eight". That's horrible by itself in multiple ways.)

User avatar
firechicago
Posts: 621
Joined: Mon Jan 11, 2010 12:27 pm UTC
Location: One time, I put a snowglobe in the microwave and pushed "Hot Dog"

Re: Coding: Fleeting Thoughts

Postby firechicago » Mon Aug 17, 2015 11:17 am UTC

ahammel wrote:
What's surprising about that? Are you expecting it to just fail entirely?
Yes, that is exactly what I would expect to happen when trying to multiply something that is clearly not a number by three.

Alternatively, lots of languages have:

Code: Select all

"a" * 3 == "aaa"


which at least returns another string, rather than a number.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Mon Aug 17, 2015 1:10 pm UTC

The Great Hippo wrote:Better still:

Code: Select all

>>> x = "2"
>>> x * 4
>>> x
"eight"

The hard part would be getting `"eight" * 2` to be `"sixteen"`: parsing is harder than printing.

Still, with a bit of work, I should be able to create a `_vs` type in C++ that behaves like that. Always convert values to strings, interpret strings as integers, overload arithmetic operators.

It might amuse, having a parser run every time you add two numbers.

Then I can implement Karatsuba multiplication in it. You know, for efficiency.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

korona
Posts: 495
Joined: Sun Jul 04, 2010 8:40 pm UTC

Re: Coding: Fleeting Thoughts

Postby korona » Mon Aug 17, 2015 8:03 pm UTC

Thesh wrote:I don't think it's surprising that it works, just horrible that it works. Like eww.

Unlike auto conversion when doing arithmetic I don't think stringifying property names is a bad thing. How would you handle property access? Have two kinds of properties and replace things like getOwnPropertyNames() with getOwnStringPropertyNames() and getOwnIndexedPropertyNames()? How would you serialize that?

ahammel wrote:It's a religious war, I guess, but attempting to do arithmetic with anything that looks like a number when stringified seems like a great source of infuriating bugs.

That is an entirely different topic. Auto conversion during arithmetic operations has nothing to do with stringification of property names.

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: Coding: Fleeting Thoughts

Postby ahammel » Mon Aug 17, 2015 9:44 pm UTC

korona wrote:
ahammel wrote:It's a religious war, I guess, but attempting to do arithmetic with anything that looks like a number when stringified seems like a great source of infuriating bugs.

That is an entirely different topic. Auto conversion during arithmetic operations has nothing to do with stringification of property names.
I was referring to philip's trick.
He/Him/His/Alex
God damn these electric sex pants!

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Coding: Fleeting Thoughts

Postby EvanED » Mon Aug 17, 2015 11:34 pm UTC

korona wrote:How would you handle property access?
Like any other language that wasn't defined by a madman? o[2] would return something differently from o["2"]. Likely you wouldn't be able to access o[2] another way, though I suspect that you actually could make o.2 unambiguous.

How would you serialize that?
{2:"two"}

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

Re: Coding: Fleeting Thoughts

Postby Xanthir » Tue Aug 18, 2015 1:12 am UTC

korona wrote:
Thesh wrote:I don't think it's surprising that it works, just horrible that it works. Like eww.

Unlike auto conversion when doing arithmetic I don't think stringifying property names is a bad thing. How would you handle property access? Have two kinds of properties and replace things like getOwnPropertyNames() with getOwnStringPropertyNames() and getOwnIndexedPropertyNames()? How would you serialize that?


Note that we do indeed have that now, as JS sprouted Symbols, which are used as property keys and guarantee non-collision unless you use the same Symbol object. So we have to get*() functions, one for string properties and one for Symbol properties.
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
The Great Hippo
Swans ARE SHARP
Posts: 7368
Joined: Fri Dec 14, 2007 4:43 am UTC
Location: behind you

Re: Coding: Fleeting Thoughts

Postby The Great Hippo » Tue Aug 18, 2015 1:10 pm UTC

So, in Python, modules are actually instances of a module class. If you can get a reference to the module you're currently in, you can add attributes to that instance; furthermore, those attributes can be referred to in the 'namespace' of your current scope without referring to the module instance itself. Or, in other words:

Code: Select all

>>> import sys
>>> self = sys.modules[__name__]
>>> self.x = 5
>>> print(x)
5
This is relevant because of two things: Python has a special @property decorator that lets you modify an object's __get__ and __set__ attributes to allow for code to be executed when you get or set the values of an attribute:

Code: Select all

class SpecialX:
   
    @property
    def x(self):
        return 5
       
    @x.setter
    def x(self, value):
        pass
...which means that whenever I try to set an instance of SpecialX's x attribute, nothing happens; when I retrieve it, I will get 5.

AND, because Python allows you to change an instance's class (or even the definition of its class) whenever you feel like it:

Code: Select all

>>> myinstance.x = 0
>>> myinstance.x
0
>>> myinstance.__class__ = SpecialX
>>> myinstance.x = 0
>>> myinstance.x
5
Furthermore, you can even add a class to another class's inheritance chain (through that class's __bases__ attribute).

In short, if someone were to find a way to swap out a module instance's class (or add another class to its bases), you could theoretically do this. Python doesn't let you modify builtin classes, and it doesn't let you swap an instance's class if the instance isn't a heap-type, so this might be tricky -- but apparently there's a workaround for the former problem: forbiddenfruit.

Alternatively, you could just create a new class that inherits from the module class -- with x as a @property -- and find a way to create a module with *that* class instead of the standard module class.

EDIT: Though, actually, when you just write 'x = 5' versus 'self.x = 5', the former might not activate the attribute's __set__ feature. It depends on how scope re: class variables work.

myinstance.__class__.x and myinstance.x refer to different things -- but if I set myinstance.__class__.x, then call myinstance.x, I'll get myinstance.__class__.x. I'm somewhat certain this is how Python allows things like 'str' to be a global built-in that cannot be changed -- but also allows you to change 'str' within a given scope (by just overriding the instance attribute). In other words: mymoduleinstance.__class__.str = <built-in string function> -- so if I type str(stuff), I call the built-in string function. But if I write 'str = <MY string function>', I've just created a new attribute on mymoduleinstance (mymoduleinstance.str) -- mymoduleinstance.__class__.str is still there; the instance attribute just gets preferential treatment when I look up 'str'.

Nyktos
Posts: 138
Joined: Mon Mar 02, 2009 4:02 pm UTC

Re: Coding: Fleeting Thoughts

Postby Nyktos » Tue Aug 18, 2015 11:07 pm UTC

The Great Hippo wrote:Alternatively, you could just create a new class that inherits from the module class -- with x as a @property -- and find a way to create a module with *that* class instead of the standard module class.
You can do this with import hooks, though of course for that to work you need to arrange to have the hook installed before your module is imported. I thought I remembered a PEP for making this easier, but there doesn't seem to be one.

The Great Hippo wrote:EDIT: Though, actually, when you just write 'x = 5' versus 'self.x = 5', the former might not activate the attribute's __set__ feature. It depends on how scope re: class variables work.
IIRC, __set__ isn't called in this case. The module's global scope is hooked up directly to the module object's instance __dict__; the module object itself isn't really involved at that point. You can get similar behaviour by using an import hook to replace the dict with a custom subclass.

The Great Hippo wrote:I'm somewhat certain this is how Python allows things like 'str' to be a global built-in that cannot be changed -- but also allows you to change 'str' within a given scope (by just overriding the instance attribute).
str is an attribute of the builtins module, which is searched for names if they aren't found in the current module's global scope. If you do "import builtins; builtins.str = foobar" you can reassign it globally. (This is a very bad idea.)

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: Coding: Fleeting Thoughts

Postby ahammel » Wed Aug 19, 2015 3:43 am UTC

Some date parsing code I came across today (simplified):

Code: Select all

case monthMMM:
  "Jan" = 1;
  "Feb" = 2;
  "Mar" = 3;
  "Apr" = 4;
  "May" = 5;
  "June" = 6;
  "July" = 7;
  "Aug" = 8;
  "Sep" = 9;
  "Oct" = 10;
  "Nov" = 11;
  "Dec” = 12;


Image
He/Him/His/Alex
God damn these electric sex pants!

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6598
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Wed Aug 19, 2015 3:49 am UTC

June and July?
Summum ius, summa iniuria.

User avatar
ahammel
My Little Cabbage
Posts: 2135
Joined: Mon Jan 30, 2012 12:46 am UTC
Location: Vancouver BC
Contact:

Re: Coding: Fleeting Thoughts

Postby ahammel » Wed Aug 19, 2015 3:52 am UTC

Thesh wrote:June and July?

Yep. "Jun" and "Jul" are parse errors.
He/Him/His/Alex
God damn these electric sex pants!


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 5 guests