I'm developing a programming language called Kernel. Kernel is a conservative, Scheme-like dialect of Lisp in which everything is a first-class object.
"But," you may ask, "aren't all objects first-class in Scheme?" (I'm glad you asked.) No, they aren't. Special-form combiners are second-class objects. To borrow a phrase from the original description of first- and second-class objects by Christopher Strachey, they have to appear in person under their own names. (There are also several other kinds of second-class objects in Scheme, but special-form combiners are the most commonplace.)
What is the theoretical significance of the kernel language? What is an example of a 2nd-class object in Scheme? What is the practical advantage of all objects being first class in Scheme? Does this sound like Smalltalk a bit?
"What is the theoretical significance of the kernel language?"
Fexprs have had a bad reputation thanks to the paper "The Theory of Fexprs is Trivial." However--and this is what I've gleaned just by reading John Shutt's more propaganda-ish statements, not hard math--that paper was based on a particular formulation of fexprs, which doesn't apply to Kernel.
I think Kernel's main contribution is the idea of passing the calling environment in each fexpr call, so that it can evaluate its parameters in the correct environment and preserve lexical scope. On top of that, Kernel has some nuances to its scoping/assignment rules that oughta make it possible in most cases to determine if a variable is a constant, even if we're passing environments around to fexprs all over the place. Once we know something's a constant, we can constant-fold it and (hopefully!) turn fexpr calls that use 'eval into eval-free code, just as if the fexpr were a macro.
I say "oughta" and "hopefully" because I haven't mulled over the details enough myself to be confident.
"What is an example of a 2nd-class object in Scheme?"
Special-form combiners? :-p
What that means is things like "if" and "set!". You can't pass the "if" operator as a parameter to a function in Scheme, but in Kernel there are no exceptions like that. The "$if" variable holds an fexpr, and you can pass that fexpr to other places.
Another example used by the Kernel R-1RK is infinite lists. In Scheme, you can pass a cyclic list around in variables, but you can't actually use it as a list because standard list utilities like 'map, 'length, and 'apply don't work with it. Even if you wrote a library that did handle infinite lists, other peoples' libraries would still lag behind. (I'm not really convinced that this makes infinite lists second-class in Scheme. IMO, it just makes them less useful than finite lists.)
Another example is register use. Do you manually pass machine registers to Scheme procedures so they know which ones they're allowed to clobber? No? Well, you don't do it in Kernel either. :)
"What is the practical advantage of all objects being first class in Scheme? Does this sound like Smalltalk a bit?"
I don't see an inherent advantage, so I'm probably the wrong person to ask, for Kernel's sake. :-p To me, "first-class object" is redundant, just emphasis to distinguish objects from other things that you might think are objects but aren't.
Given a choice between two languages, where the only practical difference is that one language doesn't let you do as much with certain values (objects), the other language has a clear practical advantage. But sometimes "practical difference" depends on your point of view. To another person, given the same pair of languages, they might say the only practical difference is that one language has features they don't want or need, that actually make it harder for the language and its community to evolve in the way they prefer.
For one particular example of first-class-ness being a good idea: An awful lot of languages allow any module to access certain implicit "global" utilities. If these modules instead took their "global" dependencies as a first-class parameter, that would make it possible (if not necessarily easy, depending on the rest of the language and its community habits) to build programs that securely ran dynamically loaded outside code, using an object-capability model approach.