About ChaiScript

ChaiScript is the first and only scripting language designed from the ground up with C++ compatibility in mind. It is an ECMAScript-inspired, embedded functional-like language.

Download

Version: 2.3.2 Released: 1/18/2010

Source

Version: 2.2 Released: 11/15/2009

Windows
Linux
OS X

ChaiScript Questions

Any questions related to using ChaiScript

variable scope

var foo = 100
def barfunc()
{
  print(foo)
}
print(foo) // prints "100"
barfunc() // Eval_error, Can not find object: foo.

shouldn't `foo` be a global variable that can be resolved inside barfunc(), so calling barfunc() prints "100", too?

is this the intended behavior?

Good question

In ChaiScript there aren't global variables. You can register a constant value in your C++ application that is global, but you can't make a variable that all functions can see.

If you're curious why:

The short answer is that global variables aren't good practice.

The long answer is that we liked the idea of reusable functions in ChaiScript. The easiest way to make reusable functions is to always have a function's parameters be explicit, so you can just call it from any context and know you're passing in everything it needs.

The even longer answer is that ChaiScript is automatically thread-safe. If you take the same engine and call scripts in different threads, this should, in theory, "just work". Having global variables makes this automatic safety difficult and the implementation hairy (since now some variables would be handled differently than others).

global variables

class GlobalVariableHelper
{
public:
  Boxed_Value & __get_global(std::string const & name)
  {
    // require read-lock for thread-safe
    return _M_globalvars[name];
  }
 
  void __set_global(std::string const & name, Boxed_Value & value)
  {
    // require write-lock for thread-safe
    __globalvars[name] = value;
  }
 
private:
  std::map< std::string, Boxed_Value > _M_globalvars;
}
 
...
GlobalVariableHelper gvhelper;
chai.add(fun(&GlobalVariableHelper::__get_global, gvhelper), "get_global");
chai.add(fun(&GlobalVariableHelper::__set_global, gvhelper), "set_global");

and in chaiscript:

set_global("foo", 100); // foo = 100;
set_global("foo", get_global("foo") + 10); // foo += 10

global variable

Probably the best way to get a "global variable" is to not make it a literal variable. Instead register a getter and setter for the variable you want to be globally visible. These functions will be global, so it's up to you to maintain thread-safety, but it will be visible to all threads.

===

oops, someone edited my post instead of reply.

My bad

Who thought it was a good idea to give me admin privs? Sorry about that.

How can i expose derived classes?

How can i expose their functions to chaiscript?

class Class1
{
public:
	Class1(){}
	virtual ~Class1(){};
	void Print1(){std::cout << "Print from Class1" << std::endl;}
};
 
class Class2 : public Class1
{
public:
	Class2(){}
	virtual ~Class2(){}
	void Print2(){std::cout << "Print from Class2" << std::endl;}
};
 
Class2 * pClass2 = new Class2;
 
Class2 * getClass2(void)
{
	return pClass2;
}
 
void init()
{
	Chai.add(fun(&Class2::Print1), "Print1");
	Chai.add(fun(&Class2::Print2), "Print2");
	Chai.add(fun(&getClass2),"get");
 
}

get().Print2() works fine
get().Print1() does not - "No matching function to dispatch to" during evaluation at (1, 7)"

that should work...

I'll look into it this evening, not sure why you would have a problem with that one.

Learn something new every day

I really would have expected your example to work. It seems I'm wrong, however.

You can force the issue by telling ChaiScript exactly what type you want to work with:

class Class1
{
public:
	Class1(){}
	virtual ~Class1(){};
	void Print1(){std::cout << "Print from Class1" << std::endl;}
};
 
class Class2 : public Class1
{
public:
	Class2(){}
	virtual ~Class2(){}
	void Print2(){std::cout << "Print from Class2" << std::endl;}
};
 
Class2 * pClass2 = new Class2;
 
Class2 * getClass2(void)
{
	return pClass2;
}
 
void init()
{
	Chai.add(fun<void (Class2 *)>(&Class2::Print1), "Print1");
	Chai.add(fun(&Class2::Print2), "Print2");
	Chai.add(fun(&getClass2),"get");
}

You seem to be bubbling up the question of handling derived types, something that we have avoided up until now. We'll see what's possible.

-Jason

thanks + new Problem

Thanks, that works so far.

My new problem, taking the code from above as base:

chaiscript::ChaiScript::State backupState;
void init()
{
	Chai.add(fun<void (Class2 *)>(&Class2::Print1), "Print1");
	Chai.add(fun(&Class2::Print2), "Print2");
	Chai.add(fun(&getClass2),"get");
        backupState = Chai.get_state()
}
 
void ResetState()
{
	Chai.set_state(backupState);
}

User Input: "var i = 3"
Call : ResetState()
User Input: "return i" - returns 3

I would have expected "i" to not exist anymore.

Then i tryed the following:

chaiscript::ChaiScript pChai = new chaiscript::ChaiScript;
...
...
...
void ResetState()
{
        delete pChai;
        pChai = new chaiscript::ChaiScript;
	pChai->set_state(backupState);
}

That will throw an exeption as soon ResetState() is called.

Edit:

I read your statement about avoiding global vars and using functions instead. That makes perfectly sense and everything is working as intended now, as functions are reset properly.

Edit 2:

I found a memory leak

void ResetState()
{
	pChai->set_state(backupState);
        pChai->add(fun(&getClass2),"get");
}
 
PseudoMain()
{
    	while(command != "quit")
	{
		for(int i = 0; i < 200; i++)  // just a little bit extra overhead
			pChai.ResetState();
 
		if(command == "gc")
			pChai.RunFile("Test.chai");
		command = get_next_command();
 
}

What happens?

case 1: if calling eval EVERY loop, memory usage is low, nothing is leaking

case 2: if calling eval NEVER , memory usage keeps raising, here is the leak.

case 3: if calling eval CONSTANTLY each 10th loop, memory usage is higher than in case1, but seems not to leak any further

case 4: get´s complicated to explain. each time, ResetState() is Called without calling eval afterwards, memory usage will go up.
for example after 10 times ResetState(), i am calling RunFile() or whatever involves eval. After this eval, i can again call ResetState() 10 times, without increasing the memory usage. but as soon as it get´s called the 11th..... time without eval intetween memory usage will go up again.

commenting out either the set_state or add will stop this strange behaviour. but will also break my way of updating important pointers.
I solved it, by calling eval("") at the end of my Reset function.
But it doesn´t feel like beeing the proper solution...

Please log a bug report

It would be great if you could submit a bug report with complete source (both C++ and chaiscript) that demonstrate the memory leak so we can check into it.

Thanks.
Jason

Thanks for the bug report.

Thanks for the bug report. Reading over the source code it appears to me that the problem is that set_state() does not call sync_cache() ( a function which is normally called during any eval() operation ). I'll verify and test a fix as soon as I can get to it.

-Jason

2 Questions and a Suggestion

My first question is why do I get this error: "No matching function to dispatch to" on the last line when trying to compile:

var kPI = 3.141592653589793
var kSolarMass = 4.0 * kPI * kPI
var kDaysPerYear = 365.24
var dt = 0.01
 
attr Vector3::x
attr Vector3::y
attr Vector3::z
def Vector3::Vector3(x, y, z) {
    this.x = x
    this.y = y
    this.z = z
}
 
def Vector3::`+`(rhs) {
    return Vector3(this.x + rhs.x, this.y + rhs.y, this.z + rhs.z)
}
 
def Vector3::`-`(rhs) {
    return Vector3(this.x - rhs.x, this.y - rhs.y, this.z - rhs.z)
}
 
def Vector3::`*`(rhs) {
    return Vector3(this.x * rhs, this.y * rhs, this.z * rhs)
}
 
def Vector3::Length() {
    return sqrt(this.x * this.x + this.y * this.y + this.z * this.z)
}
 
def Vector3::SquaredLength() {
    return (this.x * this.x + this.y * this.y + this.z * this.z)
}
 
attr Body::position
attr Body::velocity
attr Body::mass
def Body::Body() { }
def Body::Body(x, y, z, vx, vy, vz, mass) {
    this.position.x = x
    this.position.y = y
    this.position.z = z
    this.velocity.x = vx
    this.velocity.y = vy
    this.velocity.z = vz
    this.mass = mass
}
 
 
var sun = Body(0, 0, 0, 0, 0, 0, kSolarMass)

My second question is more of an inquiry. What other language features do you plan to add?

Lastly, my suggestion. There should be an IRC chat room! :-)

Fixed in r482

We've implemented a fix that solves the naming conflict problem you were having. Don't forget to also properly initialize your members in your constructors. Since members are not typed we have no way of initializing them for your.

Your error is something of a

Your error is something of a red herring, the actual problem is that the local variables for an object type and the parameter names for the constructor are conflicting.

var kPI = 3.141592653589793
var kSolarMass = 4.0 * kPI * kPI
var kDaysPerYear = 365.24
var dt = 0.01
 
attr Vector3::x
attr Vector3::y
attr Vector3::z
def Vector3::Vector3(m_x, m_y, m_z) {
    this.x = m_x
    this.y = m_y
    this.z = m_z
}
 
def Vector3::`+`(rhs) {
    return Vector3(this.x + rhs.x, this.y + rhs.y, this.z + rhs.z)
}
 
def Vector3::`-`(rhs) {
    return Vector3(this.x - rhs.x, this.y - rhs.y, this.z - rhs.z)
}
 
def Vector3::`*`(rhs) {
    return Vector3(this.x * rhs, this.y * rhs, this.z * rhs)
}
 
def Vector3::Length() {
    return sqrt(this.x * this.x + this.y * this.y + this.z * this.z)
}
 
def Vector3::SquaredLength() {
    return (this.x * this.x + this.y * this.y + this.z * this.z)
}
 
attr Body::position
attr Body::velocity
attr Body::mass
def Body::Body() { }
def Body::Body(m_x, m_y, m_z, m_vx, m_vy, m_vz, m_mass) {
    this.position = Vector3(m_x, m_y, m_z)
    this.velocity = Vector3(m_vx, m_vy, m_vz)
    this.mass = m_mass
}
 
var sun = Body(0, 0, 0, 0, 0, 0, kSolarMass)

The above should work for you. We will see about fixing the scope problem so that this lookup/naming problem doesn't catch other people, (and should probably fix that error you are getting, to something more reasonable too).

I'll look into the IRC channel, might be hard for the main developers to keep up with, but we'll see if we can't give it a shot.

-Jason

freenode

I've started lurking on #chaiscript on freenode for anyone who happens to want to stop by. I've also registered with freenode to officially be a group, but they say registrations take a while to process.

-Jason

Fixed

This one is fixed too, in the newly released 2.3.2.

VC10 B2 Support?

Are there currently any plans to support compiling using VC10? The project I'm working on is currently utilizing VC10 so we can make use of C++0x features, and we wanted to use ChaiScript, but there are a slew of compiler errors (most of which seem to be cascading, but still...).

I took a quick look and was able to fix one or two, but I simply don't have enough knowledge about the implementation of ChaiScript to fix the rest, it would take me way too long to sit down and take in the implementation then work out what's going wrong.

VC10 support would be greatly appreciated, as going back to VC9 (aka VC 2008) is not really an option at the current time.

Thanks. Look forward to hearing from you.

MSVC Problem with Threading Disabled

Hey, when you define CHAISCRIPT_NO_THREADS the code will fail to compile under MSVC. This is due to '#warning' not being a valid preprocessor command.

I'm not sure what the equivalent is, but "#pragma message("Blah")" will print a message to the output window, so that's kind-of an alternative.

At any rate, you need to disable the use of "#warning" on MSVC or it will fail to compile. :)

Thanks.

Some more VC10 B2 problems

In boxed_value.hpp, you specialize std::swap. Under VC10, if Chaiscript's headers are included in more than one translation unit, the template specialization causes linker errors due to a redefinition of an existing function. A fix is to simply mark the function as 'inline'. Unfortunately I don't know if the standard permits you to do that, or what the exact rules are for specializing std::swap, so I'll leave that up to you. However I assume that would be a legitimate fix, as typically defining functions in header files means you need to mark them as inline or for them to be templates in order to avoid linker errors.

The second is that if Boost.Signals2 has its headers included AFTER ChaiScripts, then you will get compiler errors.

To work around this (because I use Boost.Signals2 in my application), I simply make sure to always include Signal2's headers before ChaiScript's. I'm not sure of the actual problem here, so again, I can't really give you a solution and I'll leave that for you to decide.

Sorry to be a pain. :(

Thanks for being so helpful though.

P.S. There's one more potential issue I'm investigating, but it's hard to reproduce and I'm not even sure yet if it's my fault or ChaiScript's fault. If it's an actual issue I'll post again with more info, otherwise don't worry about it, it's probably a non-issue.

Fixed and fixed. These two

Fixed and fixed.

These two problems were generic to all compilers, took me a few minutes to track down the second one, and I just removed the std::swap specialization. I'm still a little confused about that one, since it was written as a template specialization, not just as an overload.

Oh well.

Thanks. As I said though, you

Thanks.

As I said though, you could've kept the specialization by simply marking it as inline. That would stop the linker errors.

Why did you decide to instead pull the specialization? I'm not questioning your decision, as obviously you're the expert when it comes to the implementation of ChaiScript, I'm just curious..

Followup

Hey, I think I have indeed found another issue with ChaiScript (unless I'm missing something).

My project makes use of quite a few DLLs, and about 3 of those DLLs need to have access to ChaiScript. Previously when I was using Lua and LuaBind in a similar situation, I simply passed around a pointer to the LuaBind instance (or rather, a class containing that instance, along with some extra data).

However, when I try to do that with ChaiScript I'm getting some very nasty access violations.

The problem manifests itself in two situations:
1. When I use a global ChaiScript object (i.e. static) that is NOT function local. The reason it matters whether it's function local is that the problem seems to manifest itself when the object is created "too early". The problem manifests itself when ChaiScript is created too early, I don't know what "too early" exactly is, I just know that if I defer creation of the ChaiScript object until first use, there is no problem. I can do this by either using a pointer to the ChaiScript instance and allocating it at first use, or using a local static instance.

2. Above, I noted that if I allocate the ChaiScript instance at first use, then the problem goes away. This is true, but only if the module using the object is the one that allocated it. As soon as I give the pointer to another module to use, I get the access violation again. I am compiling all modules with the same settings, so that should not be an issue, and that worked fine when I used to use LuaBind...

I'm happy to provide more information and sample code if necessary. Right now I have no idea what's going on.

Also, I should mention, the two errors I outlined above are fairly minor. This one however is critical. If I can't work out how to fix this I don't think I'm going to be able to use ChaiScript, which would be extremely unfortunate as I've grown quite accustomed to it in my (albeit short) use of it. So, help with this matter would be greatly appreciated.

Thanks.

P.S. I don't know whether this is relevant, but if you're trying to reproduce this error, you may need to know that my DLLs are not loaded 'normally'. They are 'injected' into another application. This in itself should not cause any issues though, because I'm making sure to do it safely. (I'm avoiding any potential problems which may be caused by doing anything dangerous in DllMain, by doing NOTHING in DLLMain, and opting instead to use a named export which is called once the module is fully loaded, hence making it safe to allocate any resources I want/need.)

You're getting outside of my

You're getting outside of my knowledge for windows programming, so I'm something at a loss a to how to help you with this one, unless you can provide a succinct example to reproduce the problem.

That said however, I'm guessing that your problems stem from our automatic thread context handling which is based on a static thread local storage objects.

If that's the case, you may be able to work around it by compiling with CHAISCRIPT_NO_THREADS, which I'm guessing IS an option for you, since you had swapped lua out for ChaiScript.

Let me know if this helps at all.

That's actually not a bad

That's actually not a bad suggestion...

Thanks, I'll give that a try, and if it doesn't work I'll try to get together some basic code to try and reproduce it. It may be a little while though as I'm relocating to a different country quite soon so most of my time is spent preparing that.

Thanks again, hopefully that's the issue, and if it is, I might even be able to work out a fix.

Installing VC++ 2010 B2 now,

Installing VC++ 2010 B2 now, I'll look into it.

Thank you very much. :)

Thank you very much. :)

Fixed in r472

Please see the revision notes: http://code.google.com/p/chaiscript/source/detail?r=472

ChaiScript compiles and runs but there is an outstanding conflict between boost::function and std::tr1::mem_fn as provided by Beta2, that you may run into in your own code, as exposed to ChaiScript.

Hrm, I just compiled

Hrm, I just compiled Chai-Example with MSVC2010 and I'm getting an exception thrown (and hence a crash) on the following lines when run:
Line 147 - chai("print(\"This should be true.\"); print(nullvar.is_null())");
Line 171 - chai.eval("x.attr = \"hi\"");
Line 172 - chai.eval("print(x.attr)");

Let me know if you need more info.

not a problem

Those are problems in example.cpp, not in ChaiScript itself. I checked in a new version of that file that does not have any unhandled exceptions.

Thanks again for the help.

Thanks again for the help.

Gallery Projects

We are looking for projects to put in our new project gallery, if you provide some details we will probably add your project as well (you can use the contact us link if you would like).

Thank you for the quick

Thank you for the quick resolution and the explanation.

Namespaces

Any plans for namespaces?

Something like gui.verticalLayout or gui::verticalLayout would be much nicer than hardcoding the name as gui_verticalLayout.

operator overloads

The short answer is that C++ operators are just functions. So, one option is to register them as such:

chai.add(fun(&MyClass::operator<), "<");

The above gets a bit tricky if your operator is a free function instead of a member, making it become something like:

chai.add(fun<bool (const MyClass &, const MyClass &)>(&operator<), "<");

A third option, which is not yet recommended, is to use the internal helpers that we have:

chai.add(fun(&bootstrap::detail::less_than<const MyClass&, const MyClass&>), "<");

The helper works for class methods or free functions, but it is in the "detail" namespace, which is not part of the public API.

A better option would be if we were to add helpers for all canonical forms of the operators. This would not be terribly difficult, and I will make a note to work on it for the next release. I'm envisioning something like:

chai.add(less_than<MyClass&>());

OK interesting, thanks :)

OK interesting, thanks :)

Operator overloading

Apparently the newest version supports operator overloading, but how does it work? I cannot find a sample demonstrating the functionality.

Operator overloading

It was a late add, but we should probably take some time to document it. The unit tests that covers it look like:

Use operator as a method:

def Bob::`+`(y) { this.x + y.x }
def Bob::Bob() { }
attr Bob::x
var b = Bob()
var c = Bob()
b.x = 4
c.x = 5
print(b+c)

And... operator as a function

def Bob::Bob() { }
attr Bob::x
def `-`(a, b) : is_type(a, "Bob") && is_type(b, "Bob") { a.x - b.x }
var b = Bob()
var c = Bob()
b.x = 4
c.x = 5
print(b-c)

Interesting, but how would

Interesting, but how would you bind C++ defined operators?

Implicit sharing of values

ChaiScript, unlike most scripting languages, seems to implicit *copy*, not share, all values. This is a major problem because you end up with the following problem:

// share a value with C++ and Chai, nice!
var someValue = someSharedPtrFromCPP()
 
// make another reference to this value
var theSameValue = someValue
// WOOPS, error! the shared_ptr isn't copied, but the value is copied instead
// and if you don't have a copy constructor for that value type, then you're screwed

The above problem becomes much more important when you do something like this:

def doStuff(obj)
{
    obj.val = 42
}
 
var obj = someSharedPtrFromCPP()
 
doStuff(obj) // oh no!

I propose the following:

var obj = foo()
var sharedObj = obj // shared, no copy constructor is needed
 
var copyObj = foo(obj) // explicit copy, *not* shared with the original obj

Edit:

Actually, this seems to be a non-issue. Function parameters seem to be implicitly shared, and there exists a completely obscure operator called ":=" which does sharing instead of copying. The documentation doesn't seem to mention this operator at all, I had to look through the source to find it.

There was much debate about

There was much debate about this topic before we publicly released ChaiScript. ChaiScript differs from many other scripting languages in that it does not handle built in types and object differently. We did initially have all assignments be references, but it ended up resulting in some unexpected behavior regarding the sharing of references. A simple "weird" example:

var i = 5;
var v = [1,2,4];
v[0] = i;

With all types using implicit references, it was odd to have both v[0] and i sharing a reference.

I'll make sure the docs are updated to include this information.

Some other issues

Cool, thanks. Some other issues I've noticed:

1) there doesn't seem to be any way to tell if a variable is "unknown" or correctly set. This is easily fixed by binding your own "is_unknown" function that returns Boxed_Value::is_unkown(), but it would be nice if this feature was built in like "to_string" is

2) similar to the above, there doesn't seem to be any way of checking for a "null" pointer. For example:

boost::shared_ptr<someClass> foo; // null pointer
chai.add(var(foo), "foo");
foo.doStuff() // woops, it's null - but how can we check?

3) at first I thought that Boxed_Value::get() would return a boost::any with the value of the object, but after looking through the code it seems to return the boost::any that has a reference or a shared_ptr to the value. I understand why this is done, but it would be useful if there was a value-based boost::any. For example:

void doCommand(const string &cmd, const boost::any &param0, const boost::any &param1) // or a vector of any's
{
   // do stuff with cmd and the proper parameters, assuming they hold value types, not shared_ptrs
}

If there was a way to get the value-based boost::any out of a Boxed_Value, the above would be very easy... but there isn't, because the any holds a reference or shared_ptr.

Something like this would work:

template<typename T>
T custom_cast(const boost::any &a)
{
    try
    {
        // try value type first
        return boost::any_cast<T>(a);
    }
    catch (...)
    {
    }
 
    try
    {
        // try pointer type second
        return boost::any_cast<boost::shared_ptr<T> >(a);
    }
    catch (...)
    {
    }
 
    throw bad_cast();
}

But then we have the issue of const-correctness, etc. Perhaps there is an easier, more integrated way of doing this...

is_unknown, etc

1) Added a bug tracker item for this, shouldn't be a problem
2) see 1)
3) There is a wide range of conversions built in to ChaiScript's C++ side. The short story is that Boxed_Value is really meant to be an opaque type. If you'll notice, I did not document any of its methods in the C++ online documentation.

The idea is that all interactions with Boxed_Values should occur through the boxed_cast function. I need to provide documentation for the full set of casts that are possible, but you should generally be able to extract anything you want:

boxed_cast<Type>(bv);
boxed_cast<Type &>(bv);
boxed_cast<const Type &>(bv);
boxed_cast<shared_ptr<Type> >(bv);
boxed_cast<shared_ptr<const Type> >(bv);
boxed_cast<const shared_ptr<Type> &>(bv);
boxed_cast<const shared_ptr<const Type> &>(bv);

If the boxed_value was instantiated with a boost::reference type then the shared_ptr casts are not possible. Const correctness is honored. If you instantiate it with a const type, you cannot extract non-const.

With these available casts, you should be able to extract any information you would need to at run time.

Correct, my point is that

Correct, my point is that there is no direct Boxed_Value -> boost::any conversion, you need to know the held type. Meaning I can't bind a function like this:

void doCommand(const string &name, const boost::any &value) { ... }

So if I understand properly,

So if I understand properly, you want the system to automatically extract the contained shared_ptr value or boost::reference and convert that to a boost::any?

If the Boxed_Value actually contained a boost::any (which should be a perfectly valid thing to do), then this operation should work fine.

If it does not contain a boost::any, I'm at a loss as to why you would want to do this. You can register a function that takes a Boxed_Value, which is the generic way of looking at a type-erased value inside of ChaiScript.

"You can register a function

"You can register a function that takes a Boxed_Value," right, but I can't change the interface ;) I'm saying that since both Boxed_Value and boost::any can hold 'any' value, it would be useful to have a direct Boxed_Value -> boost::any conversion. This isn't a major show stopper, just thought I'd point it out.

Question

I would like to have single instance of chaiengine used from multiple threads (engine initialization takes a while)
however thread might create their own versions of same functions.

what would be cool is to have ability to run script and add functions to a custom scope (temporary possibly)

something like:

static ChaiScript g_chai;

void thread_func()
{
int threadvar;
ChaiScriptScope chaiscope = g_chai.createScope();
chaiscope.add(chaiscript::fun(bind(&myFunc,threadvar,_1,_2)));
chaiscope.eval("script");
}

this way all my threads can use global calls in scripts and still can have same set of local
calls.

Couple other issues (IMHO)

one can't start script with {
it will cause parse error

also if (1) is invalid (that might not be an issue if one is required ot do if (true) or something.

Issues

Good points!

The first issue should be working better in the latest subversion.

The second issue: currently we don't "pun" on types, so you would need to do "if (true)" instead of "if (1)" though we might add value puns like that in the future.

Hex values in script

it seems like ChaiScript (2.0) cant recognize/parse hex numbers. is that the case or am i looking at some other issue ?
(hex numbers as 0x10 etc...)

Should be working now

This should be available in the next release. If you would like to get it earlier and don't mind using code fresh out of subversion, the most recent revisions should allow for hex and octal.