Google Collections talk, Aug 6 at the Googleplex
The
Google Tech Users Group is hosting a talk that will interest Java developers:
Overview:
How the Google Collections Library builds on java.util to provide more building blocks for doing your job.
Where:
Building 42 of the Googleplex, Mountain View, California
When:
6:00pm Food, social, demos and announcements
7:00pm Talk by Kevin Bourrillion
If you'll be in the valley, you can
register for the free event. After the talk, please join us for beers 'n' boardgames!
# posted by Jesse Wilson
on Thursday, July 31, 2008
4 comments
post a comment
Correctness and my wife
I do this really annoying thing when I'm hanging out with my wife. I correct her when she uses the "wrong" words...
We're walking around town when we see something out of the ordinary - like a humongous fat dog or a friendly hobo or a police chase.
Her: "That was random"
Me: "It was unexpected. Nothing really random about it."
Her: "Ohhkayyy programmer boy. It was random. Get over it.
Our apartment is in a bit of a ghetto. So we're lying in bed and we can hear another loud argument between the neighbours downstairs. That couple has one of those dramatic relationships and they break out in yelling one night every month or so.
Me: Jodie, why are you so anxious? Get some sleep, gotta wake up early in the morning!
Her: "I can't sleep. I'm worried."
Me: "About what?"
Her: "Lots of abstract things. For example, I'm worried that she'll pull a gun on him, and they'll shoot a bullet through the ceiling, and it will hit me!"
Me: "Huh? That's not going to happen. And if it would, it would totally hit you in the ass and then you'd have a cool story."
Her: "But I'm a worrier. I always worry about abstract things like that."
Me: "That's not abstract. It's imaginary! You're worrying about something very explicit and vivid. An abstract worry might be about say, your happiness or the future. But not getting shot in the ass. That's just imaginary."
Her: "Ohhkayyy programmer boy. It was random. Get over it.
As you can see, I'm clearly getting all caught up in anal-retentive word usage and it drives Jodie crazy. I think it's cause I read code all day and argue with my coworkers whether the method should be named
safeSubstring()
or
lenientSubstring()
. She was surprised to hear that as somebody who uses computer languages all day, I spend a lot of time thinking about words from English.
I gotta stop code-reviewing our conversations.
# posted by Jesse Wilson
on Friday, July 25, 2008
8 comments
post a comment
Two use cases - two names?
Today I did something I've never done before - I created a method that's an 'alias' to another method. I still think this is the right thing to do, but I still find it kind of weird...
Getting Providers
Binder.getProvider()
allows your module to get a
Provider<T>
while the injector is still being created. The returned provider can't be used until the injector is ready, but that usually isn't a deal breaker:
public class ListOfFiltersModule extends AbstractModule {
public void configure() {
/* get the filters set, perhaps bound with multibindings */
final Provider<Set<Filter>> filterSetProvider
= getProvider(new TypeLiteral<List<Filter>>(){});
/* use that provider in a provider instance binding */
bind(new TypeLiteral<List<Filter>>() {}).toProvider(
new Provider<List<Filter>>() {
public List<Filter> get() {
Set<Filter> filtersUnordered = filterSetProvider.get();
List<Filter> result = new ArrayList<Filter>();
result.addAll(filtersUnordered);
Collections.sort(filteresUnordered, FILTER_ORDER);
return Collections.unmodifiableList(result);
});
}
}
For this purpose, this works pretty good.
Listing Dependencies
There's another use case for
getProvider
- making dependencies explicit. It's handy to include the list of bindings that a module
wants right in the module. This helps Guice to fail-faster if a required binding is missing. More importantly, it makes the dependency obvious to the maintainers of the code:
public class DeLoreanModule extends Module {
public void configure() {
/* bindings needed from other modules */
getProvider(FluxCapacitor.class);
getProvider(TimeCircuits.class);
/* our bindings */
bind(Car.class).toProvider(DmcCarProvider.class);
}
This is okay,
but a clarifying comment is necessary here. Otherwise the
getProvider
call looks out of place - the maintainers you're trying to help may delete this "unnecessary" call!
requireBinding
Giving
getProvider
a better name for use case #2 makes the intentions more explicit. It also means we can axe the now-redundant comment:
public class DeLoreanModule extends Module {
public void configure() {
requireBinding(FluxCapacitor.class);
requireBinding(TimeCircuits.class);
bind(Car.class).toProvider(DmcCarProvider.class);
}
Behind-the-scenes, all
requireBinding()
does is call through to
getProvider()
to ensure that key is bound. But this is just an implementation detail - we could later change
requireBinding
to do something different if there was a preferred alternative.
Multiple Names
We have two use cases and two names. But only one implementation! I think it's legit, but it's a bit surprising. Where else does this come up?
# posted by Jesse Wilson
on Thursday, July 24, 2008
5 comments
post a comment
Don't create multiple annotations with the same simple name
Nobody reads imports. Good IDEs do their best to pretend imports don't even exist - they'll hide 'em from you, and manage them for you. They'll even add imports on demand when you're writing new code.
Suppose you create your own, say
@Inject
or
@RequestScoped
annotation. In the code, it's practically impossible to differentiate between this and a Guice-supplied annotation:
package com.publicobject.pizza;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.publicobject.pizza.annotation.RequestScoped;
import com.publicobject.pizza.annotation.Inject;
import com.publicobject.pizza.geography.GeographyService;
import com.publicobject.pizza.hr.EmployeeRoster;
@RequestScoped
public class PizzaStore {
@Inject PizzaStore(GeographyService geography,
EmployeeRoster workers) { ... }
}
Your head will explode debugging problems if the wrong annotation is applied. Guice can detect
some problems (blowing up on a mismatched scope annotation) but it's still risky business.
# posted by Jesse Wilson
on Monday, July 21, 2008
2 comments
post a comment
TypeResolver tells you what List.get() returns
It's diminishingly rare that I get to write code that improves the internals of both
Glazed Lists and
Guice...
Glazed Lists' BeanProperty
BeanProperty is a convenient utility class that can expose a JavaBeans getter/setter property as its own object. You give it a class (like
Baz.class
) and a property name (like "bar") and it gives you a full property object - you can use it to read and write the property. It even exposes the property's type:
class Baz {
private String bar;
String getBar() {
return bar;
}
void setBar(T bar) {
this.bar = bar;
}
}
public void testBaz() {
Baz baz = new Baz();
BeanProperty<Baz> bar = new BeanProperty<Baz>(Baz.class, "bar");
assertEquals(String.class, bar.getValueClass());
bar.set(baz, "hello");
assertEquals("hello", baz.getBar());
}
Eric Burke reported
a bug where
BeanProperty
wasn't doing the right thing for generic properties. In this example, we report the value type of Foo.bar as
Object.class
rather than
String.class
:
class Foo<T> {
T getBar();
}
class Baz extends Foo<String> {}
In order to get the return type of
Baz.getBar()
, we need to map Foo's type parameter
T
to
java.lang.String
.
Guice's ProviderMethods
The upcoming release of Guice lets you specify bindings with annotated methods:
class BarProviderMethods {
@Provides @Singleton
Bar provideBar() {
Bar result = new Bar();
result.setBaz("hello");
return result;
}
}
...but we run into problems if users specify generic provider methods. Guice wants to bind the return type of the provider method. Unfortunately, due to generics, that type might be insufficient:
class SetProviderMethods<T> {
@Provides
Set<T> provideSetOfT(T onlyElement) {
return ImmutableSet.of(onlyElement);
}
}
Enter TypeResolver
This class takes a generic type (like
ArrayList<String>
) and exposes
precisely what the return types will be:
public void testTypeResolver() {
Type listOfString = new TypeLiteral<List<String>>() {}.getType();
Method getMethod = List.class.getMethod("get", int.class);
TypeResolver resolver = new TypeResolver(listOfString);
assertEquals(String.class, resolver.getReturnType(getMethod));
}
I suspect this class is generally useful for any app that uses a reasonable amount of reflection. If this is useful to you, grab the source from
Guice SVN.
# posted by Jesse Wilson
on Sunday, July 20, 2008
0 comments
post a comment
The reasons I'm not on iPhone
It's really tempting. As far as devices go, iPhone 3G is the best there is. It's a generation ahead of its competitors, and the gap is growing. The app store is great for both developers and for its users. But I'm not gonna get one:
Amazon MP3. Lots of good songs with no 'deregister this computer' nonsense. But Amazon MP3
cannot compete with iTunes on Apple's platform—third party apps can't download while I surf the web. This also kills movie and video downloads.
Skype. Voice-over-IP is forbidden on the iPhone 'cause AT&T wants to bill voice traffic at a different rate than data. Even on my home network, AT&T would prefer I pay them for each minute of each call. I want net neutrality but the iPhone won't have any of it.
Flash and Java. That means no Line Rider, Hulu, Naval Command or flexgames.com. Apple would prefer for developers to write iPhone-only apps rather than phone-independent apps. This is good for Apple but bad for developers.
The iPhone is a lock-in platform. Sorry, Apple, but I'm not ready for that level of commitment.
# posted by Jesse Wilson
on Friday, July 18, 2008
9 comments
post a comment