How to concatenate strings ?

Nonon's icon

Hi everybody, i'm a newbie in max and i'm already facing a problem :(
I need to concatenate strings (symbols if you prefer) from 2 diferent lists and them send them over OSC to other applications (e.g. Eyesweb).

For instance i've got a message box with [UUID00 UUID01 UUID02...UUIDnn] and another message box with [TLM-LUIS TLM-JOSE TLM-XPTO ...] my gold is to join these elements into a third list like [UUID00TLM-LUIS UUID01TLM-JOSE ...] and then send them over by OSC

Can anyone help me out ? plzzzz :)
Regards

Nonon

VG's icon

you can use sprintf

VG's icon

Jasch has also made a lib for such things
www.jasch.ch/dl/default.htm

another good thing to do is to read the manual,
and search in the forum if your question has
not been asked thousands of times...
or you'll soon learn what RTFM and STFW mean ;-)

cheers
vg

Peter Castine's icon

On 22-Mar-2006, at 13:02, Nuno wrote:

> For instance i've got a message box with [UUID00 UUID01
> UUID02...UUIDnn] and another message box with [TLM-LUIS TLM-JOSE
> TLM-XPTO ...] my gold is to join these elements into a third list
> like [UUID00TLM-LUIS UUID01TLM-JOSE ...] and then send them over by
> OSC

Look at zl (partic [zl iter]) and sprintf.

nick rothwell | project cassiel's icon

On 22 Mar 2006, at 12:02, Nuno wrote:

> I need to concatenate strings (symbols if you prefer) from 2
> diferent lists and them send them over OSC to other applications
> (e.g. Eyesweb).

As others have already hinted, [sprintf %s%s] will do what you want.

However, if you're going to have arbitrary combinations of symbols,
every combination symbol is going to go into Max's symbol hash table
- forever. This may or may not affect performance.

    -- N.

nick rothwell -- composition, systems, performance -- http://
www.cassiel.com

Nonon's icon

Tnx to you all :)

I did searched the forum with "concatenate strings" keywords and didn't found nothing...but since my net acess is so lousy i'm not sure of anything...as for the manual, i've got a printed version and stinks, no sprintf, i've started to read the pdf latest (and complete) version.

I've checked the sprintf and i'm sure it will do fine , as for the jasch lib, well, tnxs again for the tip: it's a very cool one and i'm downloading it right now...

Best Regards

Nonon

John Nowak's icon

On Mar 22, 2006, at 7:58 AM, Nick Rothwell wrote:

> As others have already hinted, [sprintf %s%s] will do what you want.
>
> However, if you're going to have arbitrary combinations of symbols,
> every combination symbol is going to go into Max's symbol hash
> table - forever. This may or may not affect performance.

What's the rationale here for Max's implementation of symbols? This
doesn't make much sense to me.

- John

nick rothwell | project cassiel's icon

On 22 Mar 2006, at 23:07, John Nowak wrote:

> What's the rationale here for Max's implementation of symbols? This
> doesn't make much sense to me.

You mean, the rationale for permanently hashing them?

Fast lookup and comparison. Max uses symbols for ... well,
everything, really.

    -- N.

nick rothwell -- composition, systems, performance -- http://
www.cassiel.com

Peter Castine's icon

Further unto: string comparison is slow. Comparing pointer addresses
is fast. We can be talking as much as factor 100 here. More typically
maybe factor 20 or so, but that's still a big difference.
Furthermore, in the late 1980s this had to run on 68000s and 68020s
at 8 MHz.

Miller's implementation of symbols was puredead brilliant. Still is.

The downside to this strategy (that the hash table grows and grows
and grows and grows and grows and grows and...) is negligible in a
world of +512MB RAM.

-- P

-------------- http://www.bek.no/~pcastine/Litter/ -------------
Peter Castine | +--> Litter Power & Litter Bundle for Jitter
|....................................................
p@castine.de | iCE: Sequencing, Recording, and Interface Building
pcastine@gmx.net | for Max/MSP
pcastine@bek.no | http://www.dspaudio.com/ Extremely cool
4-15@kagi.com |....................................................
| home|chez nous|wir|i nostri http://www.castine.de/

nick rothwell | project cassiel's icon

On 23 Mar 2006, at 10:27, Peter Castine wrote:

> The downside to this strategy (that the hash table grows and grows
> and grows and grows and grows and grows and...) is negligible in a
> world of +512MB RAM.

Sure, but these days people are talking about Max/MSP for
installation works which run for months at a time. (Mine clocked in
five weeks of 24/7 operation, but that's modest these days.) If the
code is generating several distinct symbols a second (say, by
symbolising a string representation of date and time) that adds up
to ... erm ... lots. (And I don't know what computational complexity
we're looking at here - O(log N)? - but with a gazillion symbols that
must degrade somewhat.) So, it's a bad thing to do, and I always have
faint alarm bells going off whenever I see something that's
potentially synthesising dynamic symbols.

It might be nice to have some kind of built-in Max function to report
symbol table size and stats (bucket sizes and the like).

    -- N.

nick rothwell -- composition, systems, performance -- http://
www.cassiel.com

Peter Castine's icon

On 23-Mar-2006, at 13:34, Nick Rothwell wrote:

> Sure, but these days people are talking about Max/MSP for
> installation works which run for months at a time.

Point taken. Assuming you're *not* auto-rebooting once a day (which a
lot of installations do for many reasons).

Also, if the vocabulary is sufficiently limited, auto-generated
symbols will start repeating before memory becomes an issue. Nuno's
example:

>> For instance i've got a message box with [UUID00 UUID01
>> UUID02...UUIDnn] and another message box with [TLM-LUIS TLM-JOSE
>> TLM-XPTO ...]
>
could, mathematically, generate up to 45 million different symbols,
which would fill up an awful lot of RAM. But if the TLM-LUIS etc. are
limited to a couple of hundred names, then symbol table growth will
be tractable.

This all depends very much on the concrete application.

> It might be nice to have some kind of built-in Max function to
> report symbol table size and stats (bucket sizes and the like).

Or if Max time-stamped symbol usage and would start flushing unused
symbols at some point.

Or if it were possible to have a non-symbolized string data type.
There was a 3rd party add-in a while back that did this; JScript and
Java will also allow you to munge strings without stuffing the symbol
table.

J/JS are probably the most reliable options today for avoiding symbol
table explosion. If and when it's an issue.

You're right that people should think about what they're doing if
they're going to auto-generate symbols, but in a lot of cases it
doesn't rate more than blue or yellow HLS status.

-- P.

-------------- http://www.bek.no/~pcastine/Litter/ -------------
Peter Castine | +--> Litter Power & Litter Bundle for Jitter
|....................................................
p@castine.de | iCE: Sequencing, Recording, and Interface Building
pcastine@gmx.net | for Max/MSP
pcastine@bek.no | http://www.dspaudio.com/ Extremely cool
4-15@kagi.com |....................................................
| home|chez nous|wir|i nostri http://www.castine.de/

John Nowak's icon

I was more talking about the permanent aspect. Obviously string
comparisons for everything would be dog slow (which is part of the
reason we have ports in the first place rather than prepending
commands to everything I'd assume). I'd think after the current
branch was done (i.e. after sprintf is done sending to everything),
we'd be able to kick the symbol out of the hash table, no? I'm not
trying to be snarky here -- I'm genuinely curious as I'm implementing
a similar system myself. I've opted instead to do *everything* via
ports, which works fine as it is a text-based language, and it is
very fast (every "port" is just a function pointer that takes the
current "object" and the received data as arguments). Obviously using
so many "ports" is not possible with the GUI paradigm, and hence we
have the current system.

Can anyone explain why we can't manage the hash table at all?

- John

Joshua Kit Clayton's icon

On Mar 23, 2006, at 9:25 AM, John Nowak wrote:

>
> Can anyone explain why we can't manage the hash table at all?

symbols need to live for the life of the application since they are
matched by pointer comparison (i.e. fast). The pointer must remain
the same since there is no way of determining when there are no
longer any references to said symbols. One could imagine a system
which uses reference counting to "attach to" or "release" a symbol,
though it would require a complete max overhaul (and all supporting
objects) to do so. Not likely in the near future.

If you want to use strings (i.e. *not* symbols), you can accomplish
this in a number of ways--e.g. lists of integers or single letter
symbols (which would only take up a handful of symbol table slots),
or jitter matrices.

-Joshua

Stefan Tiedje's icon

This thread is interesting and important, as it shows something I was
never aware of...

Joshua Kit Clayton wrote:
> If you want to use strings (i.e. *not* symbols), you can accomplish
> this in a number of ways--e.g. lists of integers or single letter
> symbols (which would only take up a handful of symbol table slots), or
> jitter matrices.

One essential information is missing for me: where does this hashing
happen and which are the objects which actually do it.
There are these lftoa and atolf objects from the pluggo installers which
could translate strings into numbers. But if the symbol is already in
the table it wouldn't help...

One way to control the hash table eventually would be to exchange a
symbol with another one. (Not for newbies, keep it somewhere hidden in
the docs.) If you know that the symbol isn't used elswhere anymore you
might want to exchange it instead of creating a new entry in the table.
A nice opportunity to create almost untrackable bugs... ;-)

For real world applications outside of installations its probably not
important.

Stefan

--

[][] [][][] [][] [][][]
[][][][][][][][][][][][][][][]

Stefan Tiedje
Klanggestalter
Electronic Composition
&
Improvisation

/~~~~~
\ /|() ()|
))))) )| | |( \
/// _/)/ )))))
___/ ///

-------------------------x----
--_____-----------|-----------
--(_|_ ----|-----|-----()----
-- _|_)----|-----()-----------
----------()------------x-----

14, Av. Pr. Franklin Roosevelt,
94320 Thiais, France
Phone at CCMIX +33-1-57 42 91 09

nick rothwell | project cassiel's icon

On 24 Mar 2006, at 09:44, Stefan Tiedje wrote:

> One essential information is missing for me: where does this
> hashing happen and which are the objects which actually do it.

A hash entry is created (or, if it exists, retreived) by any external
object, or part of Max/MSP proper, which makes a kernel call to gensym
() - in other words, it happens all over.

Re: symbol exchange: the point of hash tables is that they use hash
values, designed to produce as few collisions as possible; it's not
possible to exchange a symbol in-place in the table. Or am I
misunderstanding your suggestion?

    -- N.

nick rothwell -- composition, systems, performance -- http://
www.cassiel.com

Peter Castine's icon

On 24-Mar-2006, at 10:44, Stefan Tiedje wrote:
> One way to control the hash table eventually would be to exchange a
> symbol with another one. (Not for newbies, keep it somewhere hidden
> in the docs.) If you know that the symbol isn't used elswhere
> anymore you might want to exchange it instead of creating a new
> entry in the table.

An interesting idea that, at its core, breaks almost all of the
object-orientation of Max.

Once an object passes a symbol out of an outlet, it can never "know
that it isn't used elsewhere anymore". To do that, your object would
have to what objects are attached and how each and every object
(including 3rd party, yet-to-be-developed objects!) that receives the
symbol handles it. Maybe someone is storing your object's symbols in
a coll. If you destroy the hash table entry, that coll will go BOOM!
and take Max down with it.

An object can, realistically, only gauge the lifespan of a character
string that it uses internally. In this case, there is probably no
need to turn the string into a symbol.

Add to this the details of hash table management--hash tables do not
generally get smaller just because a couple of entries have been
deleted--the idea is probably inpracticable at several levels.

Of course, I don't know the innards of how Max manages its particular
hash tables, so I may be going out on a limb with the above. But it
seems a pretty stable limb.

-- Peter

-------------- http://www.bek.no/~pcastine/Litter/ -------------
Peter Castine +--> Litter Power & Litter Bundle for Jitter

iCE: Sequencing, Recording & |home | chez nous|
Interface Building for |bei uns | i nostri|
Max/MSP Extremely cool http://www.castine.de
http://www.dspaudio.com/

Stefan Tiedje's icon

Nick Rothwell wrote:
> A hash entry is created (or, if it exists, retreived) by any external
> object, or part of Max/MSP proper, which makes a kernel call to gensym
> () - in other words, it happens all over.

The question then would be, where does it not happen. If an external has
a method "anything" does it happen? or does it happen if it has a method
for "symbol"? When I send a message from a message box or from sprintf,
is it already in the table? Or do I have a chance to convert it with
atolf...

> Re: symbol exchange: the point of hash tables is that they use hash
> values, designed to produce as few collisions as possible; it's not
> possible to exchange a symbol in-place in the table. Or am I
> misunderstanding your suggestion?

Yes that was the suggestion. Well, I am happy with Millers "puredead
brilliant" way of doing it as Peter explained. No real world problem here...

Stefan

--

[][] [][][] [][] [][][]
[][][][][][][][][][][][][][][]

Stefan Tiedje
Klanggestalter
Electronic Composition
&
Improvisation

/~~~~~
\ /|() ()|
))))) )| | |( \
/// _/)/ )))))
___/ ///

-------------------------x----
--_____-----------|-----------
--(_|_ ----|-----|-----()----
-- _|_)----|-----()-----------
----------()------------x-----

14, Av. Pr. Franklin Roosevelt,
94320 Thiais, France
Phone at CCMIX +33-1-57 42 91 09

Jeremy's icon

It happens everytime the kernel or an object calls gensym(), which, if
you do a Find in any of the available source code for Max objects,
happens frequently.

In effect, every message you send to the inlet of a Max object, or type
into a box is, at some point, converted to a symbol.

jb

Stefan Tiedje's icon

Jeremy Bernstein wrote:
> In effect, every message you send to the inlet of a Max object, or type
> into a box is, at some point, converted to a symbol.

In short terms, even if I send something to atolf it will be converted
because its going to its inlet. Aka no issue for patchers, only for
source coders eventually.

Stefan

--

[][] [][][] [][] [][][]
[][][][][][][][][][][][][][][]

Stefan Tiedje
Klanggestalter
Electronic Composition
&
Improvisation

/~~~~~
\ /|() ()|
))))) )| | |( \
/// _/)/ )))))
___/ ///

-------------------------x----
--_____-----------|-----------
--(_|_ ----|-----|-----()----
-- _|_)----|-----()-----------
----------()------------x-----

14, Av. Pr. Franklin Roosevelt,
94320 Thiais, France
Phone at CCMIX +33-1-57 42 91 09

Jeremy's icon

Yes. I wouldn't worry too much about the symbol table.

jb