1. map anomaly

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

new topic     » topic index » view message » categorize

2. Re: map anomaly

bugmagnet said...

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] 
 
new topic     » goto parent     » topic index » view message » categorize

3. Re: map anomaly

DerekParnell said...
bugmagnet said...

... 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.

DerekParnell said...

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

new topic     » goto parent     » topic index » view message » categorize

4. Re: map anomaly

bugmagnet said...

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.

bugmagnet said...

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

new topic     » goto parent     » topic index » view message » categorize

5. Re: map anomaly


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

new topic     » goto parent     » topic index » view message » categorize

6. Re: map anomaly

eukat said...


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.

new topic     » goto parent     » topic index » view message » categorize

7. Re: map anomaly

jimcbrown said...
eukat said...


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

new topic     » goto parent     » topic index » view message » categorize

8. Re: map anomaly

WhatEverNickYouLikeHere said...
jimcbrown said...
eukat said...


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).

new topic     » goto parent     » topic index » view message » categorize

9. Re: map anomaly

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

new topic     » goto parent     » topic index » view message » categorize

10. Re: map anomaly

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

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu