Creating contexts

Q&A's, tips, howto's
Locked
pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Creating contexts

Post by pjot »

Hi,

With my current program I like to dynamically create a context whose name is held in a variable.

E.g. suppose I want to create the context "DEMO", normally I would do something like this:

(new MAIN DEMO)

In this case I copy the complete MAIN context to DEMO. Now, suppose this name "DEMO" is held in a variable, what do I need to do to create that context?

(set 'var "DEMO")
(new MAIN var)


This does not work, neither these:

(set 'var "DEMO")
(new MAIN 'var)

(set 'var "DEMO")
(new MAIN '(eval var))


The other way around is possible, that is, variables can contain names of existing contexts. But with my current program I do not know in advance how my contexts are going to be named.

Anybody a suggestion on how to do this?

Thanks,

Peter

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

This is probably one of more solutions ->

(context 'NEWLISP:does "rule")
(context (sym NEWLISP:does))

(context? rule)
> true

Norman.
-- (define? (Cornflakes))

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

I see:

(set 'var "DEMO")
(new GUI (sym var))
(println (context? DEMO))

...returns true! Nice, thanx.

Peter

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

Perhpas a function like "LIT" could make a return from 'SYM or 'QUOTE
a word like ->

(set 'HELLO:world "people")
(lit (sym HELLO:world)
> 'people


A reverse 'quote like ->

(quote 'myself) -> myself
(rquote "myself") -> 'myself
(rquote '(myself) -> 'myself

Norman.
-- (define? (Cornflakes))

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

The second parameter of 'new' has to be a symbol, so you could do:


(set 'var 'DEMO) ; put the symbol DEMO into var

(new GUI var) ; make context DEMO as copy of GUI

now the context DEMO is a copy of the context GUI

Lutz

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Thanks for your remarks Lutz, but I need to create a context whose name is held in a variable...

Anyway, I also observed this:
(define (create c)
(set 'ct (sym c))
(new MAIN ct)
(println (context? DEMO)) <-----ok, returns TRUE
(setq t (eval ct)) <-------------------------------------?? Why ??
(println (context? t)) <-----------ok, returns TRUE
(set 't:widget "hello world")
)

(set 'var "DEMO")
(create var)
(println DEMO:t) <-----------------------ok, returns "hello world"
So for some reason I have to evaluate the symmed 'ct' to a new variable in order to use variables in that new context? The last line "(println DEMO:t)" really has the "hello world" as output, and this is what I want.

Peter

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

(setq t (eval ct))

you want 't' to be the context, but 'ct' is a symbol, because before there is:

(set 'ct (sym c))

You could change the function 'create' to take a symbol:

Code: Select all

(define (create c)
  (set 'ct c)
  (new MAIN ct)
  (setq t (eval ct)) 
  (set 't:widget "hello world")

; and then do

(create 'DEMO)
DEMO:widget => "hello world"
But may be you have 'DEMO' only as a string at that point, then of course the original version of 'create' is better.

Lutz

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Aah yes I made a stupid typo... I actually meant this:

Code: Select all

(define (create c)
(set 'ct (sym c))
(new MAIN ct)
(setq t (eval ct))
(set 't:bla "hello world")
)

(set 'var "DEMO")
(create var)
(println DEMO:bla) <-----------------------ok, returns "hello world"
Ok thanks, I have got it working now. Too much programming confuses the mind... ;-)

Peter

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Hi Lutz,

Now I found another thing. If I have this code:
#!/usr/bin/newlisp

(context 'DEMO)

(define (echo)
(println "Hello world")
)

#-----------------------------------

(context 'MAIN)

(define (func)
#(println (context? refer)) <-------- Remove the hash later
(refer:echo)
)

# Setup var with new contextname
(set 'c "ANOTHER")
# Create new context
(set 'ct (sym c))
(new DEMO ct)
# Create context reference
(set 'refer (eval ct))

(func)

(exit)
Now I receive an error: "symbol is protected in function set : refer". But if I remove the hash in the line "#(println (context? refer))" then all works fine.

It appears that newLisp updates it's internal housekeeping with the 'context?' function. Is there a way to make this run without doing so, e.g. without the "context?" function?

Peter

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

When newlisp sees 'refer' the first time in the expression (refer:echo) it will create 'refer' as a context, not as a context variable as you intended.

Having the the statement (println (context? refer)) before, simply forces 'refer' to be created as a normal variable and then after in (refer:echo) 'refer' is understood as a variable which holds a context, which is what you want.

You could do:

Code: Select all

(define (DEMO:echo) (println "Hello World"))

(define refer) ; force it to be created as a variable

(define (func) (refer:echo) ; refer taken as variable

(new DEMO 'ANOTHER) 
; or if you have a string
(new DEMO (sym "ANOTHER"))

(set 'refer ANOTHER)

(refer:echo) => "Hello World")
normally the context variable will be a parameter in a function and then the whole issue never comes up:

Code: Select all

(define (DEMO:echo) (println "Hello World"))

(define (func ct) (ct:echo))

(new DEMO (sym "ANOTHER"))

(func ANOTHER)
So the essential thing here is to tell newLISP what 'refer' is: a context or a variable hoding a context. Contexts are protected and you cannot 'set' them yo a context. If (refer:echo) is the first thing the newLISP loader ever sees, then it decides it to be a context.

Sometimes it is the other way around you want to forward reference a context. Then you have to predeclare the symbols as a contex.

Lutz

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Hi Lutz,

Thanks! That makes sense. This indeed solves the problem. But now I am going to complicate things a little bit more. Actually, the code below reflects the actual structure of my current program:

Code: Select all

#!/usr/bin/newlisp

#-----------------------------------

(context 'MAIN)

(define (create c)
	# Create new context
	(set 'ct (sym c))
	(new DEMO ct)
	(eval ct)
)

#-----------------------------------

(context 'DEMO)

# Setup var with new contextname
(define (newct txt)
	(set 'tmp (MAIN:create txt))
)

(define (echo)
	(println "Hello world")
)

#-----------------------------------

(context 'MAIN)

#(define ANOTHER)

(define (func)
	(ANOTHER:echo)
)

(DEMO:newct "ANOTHER")

(func)

(exit)
When I call "func", I receive the error "invalid function : (ANOTHER:echo)". Obviously, the echo-function cannot be found, which I find strange, since the new context is created within the MAIN context at the top.

Now according to your explanation, I need to put a (define) just before the echo-function. If I do so, it indeed solves the problem. But unfortunately, I can never uncomment the line "#(define ANOTHER)" since I do not know the actual name of the new context. That is, I do know, but I want to hide this command, for example, in the DEMO context or the first MAIN context.

Is there another way to declare the name of a context so the function "ANOTHER:echo" can be found?

Peter

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

when you call:

(DEMO:newct "ANOTHER")

then (MAIN:create txt) will be called, which will recreate all of the variables/functions in DEMO in context ANOTHER by doing:

(new DEMO ct)

But at this moment the variable ANOTHER:echo already exists because it was created when loading:

(define (func)
(ANOTHER:echo))

Now the statement: (new DEMO ct) will not overwrite the existing ANOTHER:echo unless you do:

(new DEMO ct true)

The 'true' flag tells 'new' to overwrite the existing definition of the symbol (which contained 'nil').

to make a long story short just replace:

(new DEMO ct) with (new DEMO ct true)

and your code will work creating ANOTHER as a copy of DEMO with the correct definition of 'echo' inside it

------------------ but keep on reading ----------------

If I understand you well you want to create a new context from an existing prototype DEMO, and DEMO contains a constructor function 'create' to accomplish this? You can have this shorter:

Code: Select all

(context 'DEMO)

(define (create str)
    (new MAIN:DEMO (sym str)))

(define (echo)
    (println "Hello world"))

(context MAIN)
after loading this code you can simply do:

Code: Select all

(DEMO:create "ANOTHER") => ANOTHER

(ANOTHER:echo) => "Hello world")

;; or fancier

(set 'ct (DEMO:create "MORE)) => MORE

(ct:echo) => "Hello world"
Lutz

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Thanks Lutz, this solves the problem again! Now I understand the whole concept of contexts a lot better.

That is, for my small demo program it solves. But my actual program keeps creating segfaults! Today I tried to recreate the segfault with the demoprogram but I couldn't repeat it.

So somewhere in my main program there is a stupid problem. I will hunt it down systematically by eliminating all unnecessary elements and report back to you.

Thanks again,

Peter

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Finally I've had the time to troubleshoot the issue. It appears that my program segfaults when using arrays within contexts. I have changed the demo program to this:

Code: Select all

(context 'DEMO)

(set 't_array (array 10))
(set 't_var 0)

# Create new context
(define (create c)
	(set 'ct (sym c))
	(new MAIN:DEMO ct true)
	(eval ct)
)

# Setup var with new contextname
(define (newct txt)
	(set 'tmp (create txt))
	(inc 't_var)
	(nth-set 1 t_array tmp) <-----------segfault here
)

(define (echo)
	(println "Hello world")
)

#-----------------------------------

(context 'MAIN)

(define (func)
	(ANOTHER:echo)
)

(DEMO:newct "ANOTHER")

(func)

(exit)
The use of variables is possible, as with "t_var".

But with the array the program crashes. Is there a way to work around this?

Peter

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

The problem is that 'new' and 'def-new' fail to replicate the array, until I fix this, change:

(set 't_array (array 10))

to

(set 't_array (dup nil 10))

on a big t_array list this will be slower, but at least it will work until 'new' and 'def-new' are fixed.

Lutz

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Thanks! The demo works and now also the main program works OK.

Peter

pjot
Posts: 733
Joined: Thu Feb 26, 2004 10:19 pm
Location: The Hague, The Netherlands
Contact:

Post by pjot »

Hi Lutz,

Just tested the 8.4.6 version successfully! Thanks,

Peter

Locked