Property assignment on a graph vertex using PropertyValue does not work inside a function

I created this function:

AddStone[board_Graph, v_, s : white | black | empty] :=
PropertyValue[{board, v}, VertexState] = s


This function should change the VertexState property of vertex v in graph board to one of white, black, or empty. That's simple enough, right? Then I created a graph:

board = GridGraph[{5, 5}];


But then if I execute:

AddStone[board, 8, white]


I get an error:

"Set::setraw: Cannot assign to raw object PropertyValue[{ ... ,8},VertexState]=white."

where the "..." stands for an image of the graph board, which I obviously need not draw here.

In the Documentation for PropertyValue it is stated that one can set properties this way. In fact, the code

PropertyValue[{board, 4}, VertexState] = white


does work without issuing any messages.

-

By default, a function evaluates it's arguments before plugging them into the function definition, so in effect AddStone is trying to set the property of the value of board instead of board itself. To get around this you could set the attribute HoldFirst which tells a function to substitute the unevaluated form of the first argument into the right-hand side. So for example

Clear[AddStone];
AddStone[board_ /; Head[board] === Graph, v_, s : (white | black | empty)] :=
(PropertyValue[{board, v}, VertexState] = s)

board = GridGraph[{5, 5}];


It works. But then I tried using board_Graph instead of board_ /; Head[board] === Graph and it didn't work. Why? – becko May 20 '12 at 18:01
@becko But Set does have the attribute HoldFirst, so in PropertyValue[....] = new, the whole left-hand side is held, including the Graph object. – Heike May 22 '12 at 8:22