Re: Clojure hash table accessors in CL
- From: Kaz Kylheku <kkylheku@xxxxxxxxx>
- Date: Tue, 16 Dec 2008 09:06:19 +0000 (UTC)
On 2008-12-15, Pascal J. Bourguignon <pjb@xxxxxxxxxxxxxxxxx> wrote:
André Thieme <address.good.until.2009.may.11@xxxxxxxxxxx> writes:
Slobodan Blazeski schrieb:
On Dec 14, 12:01 pm, "Leslie P. Polzer" <leslie.pol...@xxxxxxx> wrote:
Clojure, from what I've gathered, lets one access hash tables just byActually I feel that as too verbose:
referring to them in the CAR of an evaluated form:
(defparameter ht (make-hash-table))
(ht 'foo) == (gethash 'foo ht)
(ht 'foo)
->foo-val
would be even better.
Let’s say we have two hashmaps:
It's quite incredible. Why people aren't trying to add syntaxes to
languages such as pascal or C++ to be able to access maps or vectors
as if was a function call, but periodically we get asked this kind of
crapiness here?
Objects can be accessed as function calls in C++.
Please, just ignore these questions, until we see them asked in clc++ or
similarly in other cl* groups:
What can be done to be able to write:
int f(){
std::map<std::string,int> m;
m("toto")=42;
return m("toto");
}
You can't, because the operator () must be a nonstatic member
function. You can't add anything to the standard class, so that's that.
Using inheritance, we can derive a map which has a () operator:
#include <map>
#include <string>
#include <cstdio>
template <class KEY, class VALUE, class COMPARATOR = std::less<KEY> >
class fmap : public std::map<KEY, VALUE, COMPARATOR>
{
public:
// [ ... repeat every goddamn constructor like a monkey, etc. ]
VALUE &operator ()(const KEY &key)
{
return operator[](key);
}
};
int main()
{
fmap<std::string, int> fm;
fm("abcd") = 3;
printf("fm(\"%s\") == %d\n", "abcd", fm("abcd"));
return 0;
}
This is really stupid because the map actually gives you a reference (pointer
in sheep's clothing) to a storage location where you store the value.
This whole idiotic business of returning the reference to the value out of the
[] operator comes from not having the equivalent of DEFINE-SETF-EXPANDER.
You should be able to write a different method for [] when it is the target of
an assignment. Moreover, there should be a way to do an efficient operations
that combine a read with update, like what we have with SETF.
Say, what would happen if you were to capture that storage location, manipulate
the map, and then store something using the original location?
Let's change the program a little bit:
int main()
{
fmap<std::string, int> fm;
int &captured_ref = fm("abcd");
fm("abcd") = 3;
fm.erase("abcd");
captured_ref = 42;
printf("fm(\"%s\") == %d\n", "abcd", fm("abcd"));
captured_ref = 42;
printf("fm(\"%s\") == %d\n", "abcd", fm("abcd"));
return 0;
}
An old version of g++ I have lying around (3.4.3) compiles this with no
diagnostics (-Wall -ansi -pedantic).
The output?
$ ./a.out
fm("abcd") == 0
fm("abcd") == 42
What???? The fm.erase operation would have blown off the red-black tree node,
leaving captured_ref dangling. The assignment is stomping on heap
memory that no longer belongs to the reference.
C++ references are not safe pointers. It's trivial to create invalid
references in programs that compile without a peep.
What does Valgrind say when we run this program? We get better output
if we recompile for debugging with g++ -g first:
$ g++ -Wall -ansi -pedantic -g map.cc
$ valgrind --tool=memcheck ./a.out
==25907== Memcheck, a memory error detector for x86-linux.
==25907== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward et al.
==25907== Using valgrind-2.2.0, a program supervision framework for x86-linux.
==25907== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward et al.
==25907== For more details, rerun with: -v
==25907==
==25907== Invalid write of size 4
==25907== at 0x8048AED: main (map.cc:23)
This is the first assignment through captured_ref. Line 23 of main.
==25907== Address 0x1B925084 is 20 bytes inside a block of size 24 free'd
==25907== at 0x1B905043: operator delete(void*) (vg_replace_malloc.c:156)
And this is the call stack of the activation chain that deleted
the object which was being wrongly written:
==25907== by 0x80498FE: __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<std::string const, int> > >::deallocate(std::_Rb_tree_node<std::pair<std::string const, int> >*, unsigned) (new_allocator.h:86)
==25907== by 0x804939B: std::_Rb_tree<std::string, std::pair<std::string const, int>, std::_Select1st<std::pair<std::string const, int> >, std::less<std::string>, std::allocator<std::pair<std::string const, int> > >::_M_put_node(std::_Rb_tree_node<std::pair<std::string const, int> >*) (stl_tree.h:360)
==25907== by 0x8049121: std::_Rb_tree<std::string, std::pair<std::string const, int>, std::_Select1st<std::pair<std::string const, int> >, std::less<std::string>, std::allocator<std::pair<std::string const, int> > >::destroy_node(std::_Rb_tree_node<std::pair<std::string const, int> >*) (stl_tree.h:390)
[ etc ]
.
- References:
- Clojure hash table accessors in CL
- From: Leslie P. Polzer
- Re: Clojure hash table accessors in CL
- From: Slobodan Blazeski
- Re: Clojure hash table accessors in CL
- From: André Thieme
- Re: Clojure hash table accessors in CL
- From: Pascal J. Bourguignon
- Clojure hash table accessors in CL
- Prev by Date: Re: Need Help: Slime freezes at asdf:load-op
- Next by Date: Re: chaining accessors in generic function
- Previous by thread: Re: Clojure hash table accessors in CL
- Next by thread: Re: Clojure hash table accessors in CL
- Index(es):
Relevant Pages
|