1. map anomaly
- Posted by bugmagnet Aug 04, 2012
- 1324 views
So a map is an atom. Ok, have got that down pat. So how does Euphoria tell the difference between an atom created with map and a normal atom? In the following code, the map and the atom resolve to the value of 1. map() claims that both are maps. And pairs gives me the same pairs that x has when given the value of y. Anomalous, no?
include std/map.e map x = new() atom y = 1 printf( 1, "x(a map)=%d, y(an atom)=%d\n", {x,y}) printf( 1, "map(x)=%d, map(y)=%d\n", {map(x),map(y)}) sequence xpairs sequence ypairs xpairs = pairs(x) ypairs = pairs(y) if equal(xpairs, ypairs) then puts(1, "anomaly" ) else puts(1, "expected" ) end if
>maptest.ex x(a map)=1, y(an atom)=1 map(x)=1, map(y)=1 anomaly
Kind regards,
Bruce/bugmagnet
P.S. If this is a bug, I'm demonstrating my magnetism
2. Re: map anomaly
- Posted by DerekParnell (admin) Aug 04, 2012
- 1308 views
So a map is an atom. Ok, have got that down pat. So how does Euphoria tell the difference between an atom created with map and a normal atom?
It can't. Just like you can't tell the difference between the answer to 1 + 1, and the answer to 4 / 2.
This is because, the atom returned by the map:new() function is just an ordinary integer. However, that integer represents a map structure. In fact, it is merely an index into a hidden sequence, and the sequence element referenced by the map integer is what actually contains the map data.
So in effect ...
map x = map:new() atom y = 1 HIDDEN_SEQUENCE[x] is HIDDEN_SEQUENCE[y] is HIDDEN_SEQUENCE[1]
3. Re: map anomaly
- Posted by bugmagnet Aug 04, 2012
- 1271 views
... So how does Euphoria tell the difference between an atom created with map and a normal atom?
It can't. Just like you can't tell the difference between the answer to 1 + 1, and the answer to 4 / 2.
Yeah but 1+1 and 4/2 are both arithmetic expressions whereas I'm trying to differentiate between a number and reference to a map.
This is because, the atom returned by the map:new() function is just an ordinary integer. However, that integer represents a map structure. In fact, it is merely an index into a hidden sequence, and the sequence element referenced by the map integer is what actually contains the map data.
So what this seems to imply is that if I want to pass a map back from a function and differentiate it from an atom of the same value, then I have to abstract it by doing something like {ISMAP, x} and {ISINTEGER, x}. Somehow, I think I'd prefer to know the actual address, but if abstraction is the only way, so be it. Personally, though, I'm not impressed.
Kind regards,
Bruce/bugmagnet
4. Re: map anomaly
- Posted by mattlewis (admin) Aug 04, 2012
- 1239 views
Yeah but 1+1 and 4/2 are both arithmetic expressions whereas I'm trying to differentiate between a number and reference to a map.
Yes, but the reference is just a number, just like a "string" in euphoria is a sequence of numbers.
So what this seems to imply is that if I want to pass a map back from a function and differentiate it from an atom of the same value, then I have to abstract it by doing something like {ISMAP, x} and {ISINTEGER, x}. Somehow, I think I'd prefer to know the actual address, but if abstraction is the only way, so be it. Personally, though, I'm not impressed.
Yes, this is probably the only way to reliably do this with euphoria's type system.
Matt
5. Re: map anomaly
- Posted by useless_ Aug 04, 2012
- 1283 views
Give the first (or last) element of your maps a unique label, then you can test that element in that object for being a map in a type test you write.
useless
6. Re: map anomaly
- Posted by jimcbrown (admin) Aug 04, 2012
- 1266 views
Give the first (or last) element of your maps a unique label, then you can test that element in that object for being a map in a type test you write.
eukat
That won't work. Integers (and therefore the value directly stored in the map variable itself) don't have elements.
7. Re: map anomaly
- Posted by useless_ Aug 04, 2012
- 1223 views
Give the first (or last) element of your maps a unique label, then you can test that element in that object for being a map in a type test you write.
eukat
That won't work. Integers (and therefore the value directly stored in the map variable itself) don't have elements.
Your runtime type check code cannot open the map and look at the first (or last) element, thereby doing a pass/fail on opening the map and a pass/fail on the first (or last) element?
WhatEverNickYouLikeHere
8. Re: map anomaly
- Posted by jimcbrown (admin) Aug 04, 2012
- 1215 views
Give the first (or last) element of your maps a unique label, then you can test that element in that object for being a map in a type test you write.
eukat
That won't work. Integers (and therefore the value directly stored in the map variable itself) don't have elements.
Your runtime type check code cannot open the map and look at the first (or last) element, thereby doing a pass/fail on opening the map and a pass/fail on the first (or last) element?
WhatEverNickYouLikeHere
It won't be my runtime type check code in any case.
Anyways, while that is possible (I'm ignoring the difficulty of consistently ensuring that a certain value is always the first or the last element in the sequence that is used as the backing of a map), it would not have any utility in distingushing all maps from all non-map types. At the point where the code is opening the map, it is already assumed (correctly or not) that we are dealing with a map. It doesn't assist in telling if the value 1 in "map x" is a map, or if the value 1 in "integer stdout" is an integer (or a file descriptor).
9. Re: map anomaly
- Posted by ghaberek (admin) Aug 04, 2012
- 1313 views
Let me demonstrate how I use maps and it may help you understand what you can do with them.
I generally use maps to create "class-like" objects in Euphoria. Here is a quick example.
C++ code (see: Simple_class_example)
// simple_class_example.cpp class Person { public: Person(string name, int age) { this->name = name; this->age = age; } string getName() { return name; } int getAge() { return age; } private: string name; int age; }; int main() { cout << "Creating a person..." << endl; Person johnDoe("John Doe", 25); cout << "Person's name: " << johnDoe.getName() << endl; cout << "Person's age: " << johnDoe.getAge() << endl; return 0; }
Euphoria code
-- person.e namespace person include std/map.e public type person( object p ) -- make sure this is at least a map if not map(p) then return 0 end if -- verify this is a person object by checking -- that some or all of the properties exist return map:has(p, "name") and map:has(p, "age") end type public function new( sequence name, integer age ) -- create a small map to hold just a few values map p = map:new( threshold() ) -- store some values in the 'object' map:put( p, "name", name ) map:put( p, "age", age ) return p end function public function get_name( person p ) sequence name = map:get( p, "name" ) return name end function public function get_age( person p ) integer age = map:get( p, "age" ) return age end function
Testing...
include person.e procedure main() puts( 1, "Creating a person...\n" ) person johnDoe = person:new( "John Doe", 25 ) if person( johnDoe ) then printf( 1, "Person's name: %s\n", {person:get_name(johnDoe)} ) printf( 1, "Person's age: %d\n", {person:get_age(johnDoe)} ) end if atom steveSmith = 5 if not person( steveSmith ) then printf( 1, "steveSmith is not a person!\n" ) end if end procedure
-Greg
10. Re: map anomaly
- Posted by bugmagnet Aug 05, 2012
- 1264 views
Greg, that's good code and I've learned lots from it. However, it's not a solution to the problem I'm having, which has surfaced in the process of writing the euJSON library.
In the current implementation, decoding '{"key1" : {"key1.1" : 2}, "key2" : 2}' gives me a map which contains '{{"key1",2},{"key2",2}}'. At this point I don't know, programmatically, which '2' refers to a map and which refers to an atom: map() will give true to both, because maps are stored as atoms. When the map pointed to by "key1" gets unpacked, the value associated with "key1.1" is also '2' which could be a map and could be an atom and who can tell?
Maybe there's a better way of dumping the results of the map in the first place. The problem first presented in the test routine's dump() procedure:
procedure dump( object m, integer depth = 0 ) sequence p = pairs(m) for i = 1 to length( p ) do puts( 1, repeat( '\t', depth ) & p[i][1] & " ==> " ) if map( p[i][2] ) then puts( 1, "\n" ) dump( p[i][2], depth + 1) else puts( 1, special( p[i][2] ) & "\n" ) end if end for end procedure
This gets called as follows:
procedure process( sequence s ) sequence result result = decode( s ) if result[1] = -1 then dump( result[3] ) else puts(1, "Could not parse " & s ) end if end procedure process("{\"key1\" : {\"key1.1\" : 2}, \"key2\" : 2}")
In process(), result ends up with a three element sequence where the last item is the map. That map gets passed to dump(). Dump, in the first instance gets the sequence which it proceeds to iterate through. After displaying "key1" it recurses, because it recognises '2' as a map. As '2' is indeed a map the next thing to be displayed is the first key of the '2' map, which is "key1.1". Then dump() recurses again on the value of the "key1.1" pair, which happens to be '2'. This leads to an infinite recursion, indenting across the screen and displaying "key1.1 ==>" forever.
Hmm... maybe I need to memoize the dump, and permitting a once only dump of each map. Worth a try. It's that or give up on map altogether and use maybe Jiri Babor's tables http://homepages.paradise.net.nz/~jbabor/euphoria.html#misc.
Kind regards,
Bruce/bugmagnet